@gitkraken/core-gitlens 0.12.0 → 0.14.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 (198) hide show
  1. package/CHANGELOG.md +78 -1
  2. package/dist/git/cache.d.ts +84 -29
  3. package/dist/git/cache.js +188 -54
  4. package/dist/git/cache.js.map +1 -1
  5. package/dist/git/features.d.ts +1 -1
  6. package/dist/git/features.js +5 -0
  7. package/dist/git/features.js.map +1 -1
  8. package/dist/git/models/branch.d.ts +20 -2
  9. package/dist/git/models/branch.js +28 -6
  10. package/dist/git/models/branch.js.map +1 -1
  11. package/dist/git/models/reference.d.ts +3 -0
  12. package/dist/git/models/status.js +2 -2
  13. package/dist/git/models/worktree.d.ts +4 -1
  14. package/dist/git/models/worktree.js +4 -2
  15. package/dist/git/models/worktree.js.map +1 -1
  16. package/dist/git/parsers/diffParser.js +1 -1
  17. package/dist/git/providers/branches.d.ts +73 -8
  18. package/dist/git/providers/operations.d.ts +3 -2
  19. package/dist/git/providers/pausedOperations.d.ts +6 -0
  20. package/dist/git/providers/provider.d.ts +45 -2
  21. package/dist/git/providers/revision.d.ts +17 -3
  22. package/dist/git/providers/status.d.ts +8 -2
  23. package/dist/git/remotes/azure-devops.js +61 -53
  24. package/dist/git/remotes/azure-devops.js.map +1 -1
  25. package/dist/git/run.types.d.ts +12 -0
  26. package/dist/git/service.d.ts +8 -5
  27. package/dist/git/service.js +16 -8
  28. package/dist/git/service.js.map +1 -1
  29. package/dist/git/utils/branch.utils.d.ts +12 -2
  30. package/dist/git/utils/branch.utils.js +49 -5
  31. package/dist/git/utils/branch.utils.js.map +1 -1
  32. package/dist/git/utils/reference.utils.d.ts +1 -0
  33. package/dist/git/utils/reference.utils.js.map +1 -1
  34. package/dist/git/watching/changeEvent.d.ts +13 -2
  35. package/dist/git/watching/changeEvent.js +17 -3
  36. package/dist/git/watching/changeEvent.js.map +1 -1
  37. package/dist/git/watching/gitDirPoller.d.ts +111 -0
  38. package/dist/git/watching/gitDirPoller.js +266 -0
  39. package/dist/git/watching/gitDirPoller.js.map +1 -0
  40. package/dist/git/watching/provider.d.ts +16 -0
  41. package/dist/git/watching/watchGroup.d.ts +40 -4
  42. package/dist/git/watching/watchGroup.js +143 -17
  43. package/dist/git/watching/watchGroup.js.map +1 -1
  44. package/dist/git/watching/watchService.d.ts +70 -1
  45. package/dist/git/watching/watchService.js +158 -13
  46. package/dist/git/watching/watchService.js.map +1 -1
  47. package/dist/git/watching/watchSession.d.ts +44 -0
  48. package/dist/git/watching/watchSession.js +91 -6
  49. package/dist/git/watching/watchSession.js.map +1 -1
  50. package/dist/git/watching/watcherPatterns.d.ts +21 -0
  51. package/dist/git/watching/watcherPatterns.js +67 -1
  52. package/dist/git/watching/watcherPatterns.js.map +1 -1
  53. package/dist/git/watching/worktreeSummary.d.ts +34 -7
  54. package/dist/git/watching/worktreeSummary.js +39 -12
  55. package/dist/git/watching/worktreeSummary.js.map +1 -1
  56. package/dist/git-cli/cliGitProvider.d.ts +40 -2
  57. package/dist/git-cli/cliGitProvider.js +182 -18
  58. package/dist/git-cli/cliGitProvider.js.map +1 -1
  59. package/dist/git-cli/exec/commandClassifier.d.ts +15 -0
  60. package/dist/git-cli/exec/commandClassifier.js +48 -2
  61. package/dist/git-cli/exec/commandClassifier.js.map +1 -1
  62. package/dist/git-cli/exec/git.d.ts +20 -3
  63. package/dist/git-cli/exec/git.js +63 -19
  64. package/dist/git-cli/exec/git.js.map +1 -1
  65. package/dist/git-cli/exec/gitQueue.d.ts +2 -0
  66. package/dist/git-cli/exec/gitQueue.js +2 -1
  67. package/dist/git-cli/exec/gitQueue.js.map +1 -1
  68. package/dist/git-cli/exec/indexLock.d.ts +39 -0
  69. package/dist/git-cli/exec/indexLock.js +160 -0
  70. package/dist/git-cli/exec/indexLock.js.map +1 -0
  71. package/dist/git-cli/parsers/blameParser.js +2 -2
  72. package/dist/git-cli/parsers/refParser.js +4 -2
  73. package/dist/git-cli/parsers/refParser.js.map +1 -1
  74. package/dist/git-cli/parsers/statusParser.d.ts +6 -0
  75. package/dist/git-cli/parsers/statusParser.js +33 -3
  76. package/dist/git-cli/parsers/statusParser.js.map +1 -1
  77. package/dist/git-cli/parsers/worktreeParser.js +42 -2
  78. package/dist/git-cli/parsers/worktreeParser.js.map +1 -1
  79. package/dist/git-cli/providers/branchRemote.d.ts +14 -0
  80. package/dist/git-cli/providers/branchRemote.js +36 -0
  81. package/dist/git-cli/providers/branchRemote.js.map +1 -0
  82. package/dist/git-cli/providers/branches.d.ts +109 -10
  83. package/dist/git-cli/providers/branches.js +630 -134
  84. package/dist/git-cli/providers/branches.js.map +1 -1
  85. package/dist/git-cli/providers/commits.js +2 -2
  86. package/dist/git-cli/providers/config.d.ts +9 -5
  87. package/dist/git-cli/providers/config.js +58 -25
  88. package/dist/git-cli/providers/config.js.map +1 -1
  89. package/dist/git-cli/providers/contributors.js +1 -1
  90. package/dist/git-cli/providers/graph.js +9 -6
  91. package/dist/git-cli/providers/graph.js.map +1 -1
  92. package/dist/git-cli/providers/operations.d.ts +17 -0
  93. package/dist/git-cli/providers/operations.js +172 -111
  94. package/dist/git-cli/providers/operations.js.map +1 -1
  95. package/dist/git-cli/providers/pausedOperations.d.ts +8 -0
  96. package/dist/git-cli/providers/pausedOperations.js +59 -39
  97. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  98. package/dist/git-cli/providers/refs.js +11 -8
  99. package/dist/git-cli/providers/refs.js.map +1 -1
  100. package/dist/git-cli/providers/remotes.js +19 -10
  101. package/dist/git-cli/providers/remotes.js.map +1 -1
  102. package/dist/git-cli/providers/revision.d.ts +6 -2
  103. package/dist/git-cli/providers/revision.js +38 -12
  104. package/dist/git-cli/providers/revision.js.map +1 -1
  105. package/dist/git-cli/providers/staging.js +39 -14
  106. package/dist/git-cli/providers/staging.js.map +1 -1
  107. package/dist/git-cli/providers/stash.d.ts +2 -0
  108. package/dist/git-cli/providers/stash.js +33 -18
  109. package/dist/git-cli/providers/stash.js.map +1 -1
  110. package/dist/git-cli/providers/status.d.ts +3 -1
  111. package/dist/git-cli/providers/status.js +40 -22
  112. package/dist/git-cli/providers/status.js.map +1 -1
  113. package/dist/git-cli/providers/tags.js +6 -4
  114. package/dist/git-cli/providers/tags.js.map +1 -1
  115. package/dist/git-cli/providers/worktrees.d.ts +1 -0
  116. package/dist/git-cli/providers/worktrees.js +60 -31
  117. package/dist/git-cli/providers/worktrees.js.map +1 -1
  118. package/dist/git-cli/service.d.ts +6 -0
  119. package/dist/git-cli/service.js +5 -2
  120. package/dist/git-cli/service.js.map +1 -1
  121. package/dist/plus/git-github/providers/github/revision.d.ts +6 -2
  122. package/dist/plus/git-github/providers/github/revision.js +15 -10
  123. package/dist/plus/git-github/providers/github/revision.js.map +1 -1
  124. package/dist/plus/git-github/providers/github/status.d.ts +3 -1
  125. package/dist/plus/git-github/providers/github/status.js +2 -2
  126. package/dist/plus/git-github/providers/github/status.js.map +1 -1
  127. package/dist/plus/integrations/collectionMetadata.d.ts +13 -2
  128. package/dist/plus/integrations/collectionMetadata.js +14 -2
  129. package/dist/plus/integrations/collectionMetadata.js.map +1 -1
  130. package/dist/plus/integrations/index.d.ts +2 -2
  131. package/dist/plus/integrations/index.js.map +1 -1
  132. package/dist/plus/integrations/integrationService.d.ts +1 -0
  133. package/dist/plus/integrations/integrationService.js +1 -1
  134. package/dist/plus/integrations/integrationService.js.map +1 -1
  135. package/dist/plus/integrations/manager.d.ts +1 -0
  136. package/dist/plus/integrations/models/gitHostIntegration.d.ts +41 -5
  137. package/dist/plus/integrations/models/gitHostIntegration.js +106 -29
  138. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  139. package/dist/plus/integrations/models/issueReads.d.ts +17 -4
  140. package/dist/plus/integrations/providers/apiClients.d.ts +2 -0
  141. package/dist/plus/integrations/providers/apiClients.js +7 -1
  142. package/dist/plus/integrations/providers/apiClients.js.map +1 -1
  143. package/dist/plus/integrations/providers/azure/azure.d.ts +5 -4
  144. package/dist/plus/integrations/providers/azure/azure.js +36 -76
  145. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  146. package/dist/plus/integrations/providers/azure/azure.utils.js +20 -17
  147. package/dist/plus/integrations/providers/azure/azure.utils.js.map +1 -1
  148. package/dist/plus/integrations/providers/azure/models.d.ts +2 -2
  149. package/dist/plus/integrations/providers/azure/models.js +4 -4
  150. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  151. package/dist/plus/integrations/providers/azure/workItemStateCategories.d.ts +21 -12
  152. package/dist/plus/integrations/providers/azure/workItemStateCategories.js +74 -17
  153. package/dist/plus/integrations/providers/azure/workItemStateCategories.js.map +1 -1
  154. package/dist/plus/integrations/providers/azureDevOps.d.ts +44 -0
  155. package/dist/plus/integrations/providers/azureDevOps.js +108 -17
  156. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  157. package/dist/plus/integrations/providers/azureDevOpsServer.d.ts +45 -1
  158. package/dist/plus/integrations/providers/azureDevOpsServer.js +121 -6
  159. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
  160. package/dist/plus/integrations/providers/jira-server.js +18 -14
  161. package/dist/plus/integrations/providers/jira-server.js.map +1 -1
  162. package/dist/plus/integrations/providers/jira.js +18 -14
  163. package/dist/plus/integrations/providers/jira.js.map +1 -1
  164. package/dist/plus/integrations/providers/models.d.ts +1 -2
  165. package/dist/plus/integrations/providers/models.js +9 -2
  166. package/dist/plus/integrations/providers/models.js.map +1 -1
  167. package/dist/plus/integrations/providers/providersApi.d.ts +7 -17
  168. package/dist/plus/integrations/providers/providersApi.js +85 -78
  169. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  170. package/dist/plus/integrations/providers/utils/jiraIssueDrains.d.ts +22 -0
  171. package/dist/plus/integrations/providers/utils/jiraIssueDrains.js +69 -9
  172. package/dist/plus/integrations/providers/utils/jiraIssueDrains.js.map +1 -1
  173. package/dist/plus/integrations/providers/utils/providerPaging.js +8 -2
  174. package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
  175. package/dist/plus/integrations/reads/filters.d.ts +3 -3
  176. package/dist/plus/integrations/reads/filters.js.map +1 -1
  177. package/dist/plus/integrations/reads/issueBatch.d.ts +2 -1
  178. package/dist/plus/integrations/reads/issueBatch.js +1 -1
  179. package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
  180. package/dist/plus/integrations/reads/issueTracker.js +23 -14
  181. package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
  182. package/dist/plus/integrations/reads/issues.d.ts +2 -1
  183. package/dist/plus/integrations/reads/issues.js +18 -3
  184. package/dist/plus/integrations/reads/issues.js.map +1 -1
  185. package/dist/plus/integrations/reads/pullRequestBatch.js +1 -1
  186. package/dist/plus/integrations/reads/resolveRepository.js +12 -3
  187. package/dist/plus/integrations/reads/resolveRepository.js.map +1 -1
  188. package/dist/plus/integrations/reads/warnings.d.ts +11 -4
  189. package/dist/plus/integrations/reads/warnings.js +15 -5
  190. package/dist/plus/integrations/reads/warnings.js.map +1 -1
  191. package/dist/plus/integrations/results.d.ts +36 -2
  192. package/dist/plus/integrations/results.js +33 -13
  193. package/dist/plus/integrations/results.js.map +1 -1
  194. package/dist/utils/promiseCache.d.ts +10 -0
  195. package/dist/utils/promiseCache.js +17 -2
  196. package/dist/utils/promiseCache.js.map +1 -1
  197. package/docs/integrations.md +52 -20
  198. package/package.json +2 -2
@@ -10,6 +10,8 @@ export declare class OperationsGitSubProvider implements GitOperationsSubProvide
10
10
  private readonly git;
11
11
  private readonly cache;
12
12
  private readonly provider;
13
+ /** The `commonPath\0remote` pairs {@link followRemoteHeads} has handled */
14
+ private readonly followedRemoteHeads;
13
15
  constructor(context: GitServiceContext, git: Git, cache: Cache, provider: CliGitProviderInternal);
14
16
  checkout(repoPath: string, ref: string, options?: {
15
17
  createBranch?: string;
@@ -46,6 +48,18 @@ export declare class OperationsGitSubProvider implements GitOperationsSubProvide
46
48
  refspecs: readonly string[];
47
49
  preserveFetchHead?: boolean;
48
50
  }, runOptions?: GitOperationRunOptions): Promise<void>;
51
+ /**
52
+ * Writes the missing `refs/remotes/<remote>/HEAD` (the default branch the base reads) of each remote a fetch just
53
+ * read with its configured refspecs, once per remote, on git < 2.48 — newer git's fetch creates it itself. A bare
54
+ * fetch/pull reads every remote when `fetch.all` is set (git 2.44+), else its default remote. Right after the
55
+ * fetch, so the credentials it used are still cached. Never awaited; never rejects, failures not retried.
56
+ */
57
+ private followRemoteHeads;
58
+ /**
59
+ * The remote a bare `fetch`/`pull` reads: the current branch's `branch.<name>.remote` (none for `.`, the local
60
+ * repository), else the sole remote, else `origin`
61
+ */
62
+ private getDefaultFetchRemote;
49
63
  /** `remotes`, plus `heads`/`tags` for any local branch or tag the fetch writes — a `pull` fetch writes `<upstream>:<branch>` */
50
64
  private getFetchChanges;
51
65
  private fetchCore;
@@ -107,6 +121,9 @@ export declare class OperationsGitSubProvider implements GitOperationsSubProvide
107
121
  * the final default.
108
122
  */
109
123
  private throwIfSigningError;
124
+ /** Called once git has run, success or not — a rejected write can still have moved HEAD or left state behind */
125
+ private announceHeadChanged;
126
+ /** The caller has already announced the change — the conflict is what the failed run left behind */
110
127
  private createConflictResult;
111
128
  }
112
129
  //#endregion
@@ -6,8 +6,10 @@ import { normalizePath, splitPath } from "../../utils/path.js";
6
6
  import { isBranchReference } from "../../git/utils/reference.utils.js";
7
7
  import __decorate from "../../_virtual/@oxc-project+runtime/helpers/esm/decorate.js";
8
8
  import { CheckoutError, CherryPickError, CommitError, FetchError, MergeError, PullError, PushError, RebaseError, ResetError, RevertError, SigningError } from "../../git/errors.js";
9
+ import { mayWriteTracking } from "../exec/commandClassifier.js";
9
10
  import { GitErrors, classifySigningError, getGitCommandError, gitConfigsPull, inferSigningFormatFromError, maxGitCliLength } from "../exec/git.js";
10
- import { getBranchNameAndRemote, getBranchTrackingWithoutRemote } from "../../git/utils/branch.utils.js";
11
+ import { resolveBranchRemote } from "./branchRemote.js";
12
+ import { parseGitBoolean } from "./config.js";
11
13
  import { sequentialize } from "../../utils/decorators/sequentialize.js";
12
14
  import * as l10n from "@vscode/l10n";
13
15
  //#region ../git-cli/src/providers/operations.ts
@@ -16,6 +18,8 @@ var OperationsGitSubProvider = class {
16
18
  git;
17
19
  cache;
18
20
  provider;
21
+ /** The `commonPath\0remote` pairs {@link followRemoteHeads} has handled */
22
+ followedRemoteHeads = /* @__PURE__ */ new Set();
19
23
  constructor(context, git, cache, provider) {
20
24
  this.context = context;
21
25
  this.git = git;
@@ -37,12 +41,6 @@ var OperationsGitSubProvider = class {
37
41
  ...runOptions
38
42
  }, ...params);
39
43
  if (options?.createBranch) this.cache.deleteBaseBranchName(repoPath, options.createBranch);
40
- this.context.hooks?.cache?.onReset?.(repoPath, "branches", "status");
41
- this.context.hooks?.repository?.onChanged?.(repoPath, [
42
- "head",
43
- "heads",
44
- "index"
45
- ]);
46
44
  } catch (ex) {
47
45
  scope?.error(ex);
48
46
  throw getGitCommandError("checkout", ex, (reason) => new CheckoutError({
@@ -53,6 +51,8 @@ var OperationsGitSubProvider = class {
53
51
  args: params
54
52
  }
55
53
  }, ex));
54
+ } finally {
55
+ this.announceHeadChanged(repoPath, Boolean(options?.createBranch) && mayWriteTracking(ref, options?.noTracking));
56
56
  }
57
57
  }
58
58
  async cherryPick(repoPath, revs, options, runOptions) {
@@ -72,17 +72,15 @@ var OperationsGitSubProvider = class {
72
72
  }
73
73
  args.push(...revs);
74
74
  try {
75
- await this.git.run({
76
- cwd: repoPath,
77
- errors: "throw",
78
- ...runOptions
79
- }, ...args);
80
- this.context.hooks?.cache?.onReset?.(repoPath, "branches", "status");
81
- this.context.hooks?.repository?.onChanged?.(repoPath, [
82
- "head",
83
- "heads",
84
- "index"
85
- ]);
75
+ try {
76
+ await this.git.run({
77
+ cwd: repoPath,
78
+ errors: "throw",
79
+ ...runOptions
80
+ }, ...args);
81
+ } finally {
82
+ this.announceHeadChanged(repoPath);
83
+ }
86
84
  return { conflicted: false };
87
85
  } catch (ex) {
88
86
  scope?.error(ex);
@@ -112,19 +110,17 @@ var OperationsGitSubProvider = class {
112
110
  if (sign) params.push("-S");
113
111
  params.push("-F", "-");
114
112
  try {
115
- await this.git.run({
116
- cwd: repoPath,
117
- stdin: message,
118
- stdinEncoding: "utf8",
119
- errors: "throw",
120
- ...runOptions
121
- }, ...params);
122
- this.context.hooks?.cache?.onReset?.(repoPath, "branches", "status");
123
- this.context.hooks?.repository?.onChanged?.(repoPath, [
124
- "head",
125
- "heads",
126
- "index"
127
- ]);
113
+ try {
114
+ await this.git.run({
115
+ cwd: repoPath,
116
+ stdin: message,
117
+ stdinEncoding: "utf8",
118
+ errors: "throw",
119
+ ...runOptions
120
+ }, ...params);
121
+ } finally {
122
+ this.announceHeadChanged(repoPath);
123
+ }
128
124
  if (sign) {
129
125
  let format;
130
126
  try {
@@ -148,21 +144,23 @@ var OperationsGitSubProvider = class {
148
144
  const scope = getScopedLogger();
149
145
  const { branch, ...opts } = options ?? {};
150
146
  let ran = false;
147
+ let fetched;
151
148
  try {
152
149
  if (isBranchReference(branch)) {
153
- const [branchName, remoteName] = getBranchNameAndRemote(branch);
154
- if (remoteName == null) return;
150
+ const resolved = await resolveBranchRemote(this.provider, repoPath, branch, runOptions?.cancellation);
151
+ if (resolved.remote == null) return;
155
152
  ran = true;
156
153
  await this.fetchCore(repoPath, {
157
- branch: branchName,
158
- remote: remoteName,
159
- upstream: getBranchTrackingWithoutRemote(branch),
154
+ branch: resolved.name,
155
+ remote: resolved.remote,
156
+ upstream: resolved.upstream,
160
157
  pull: options?.pull,
161
158
  preserveFetchHead: options?.preserveFetchHead
162
159
  }, runOptions);
163
160
  } else {
164
161
  ran = true;
165
162
  await this.fetchCore(repoPath, opts, runOptions);
163
+ if (!opts.refspecs?.length) fetched = opts.remote != null ? { remote: opts.remote } : opts.all ? "all" : "default";
166
164
  }
167
165
  } catch (ex) {
168
166
  scope?.error(ex);
@@ -172,8 +170,46 @@ var OperationsGitSubProvider = class {
172
170
  this.context.hooks?.cache?.onReset?.(repoPath, "branches", "tags");
173
171
  this.context.hooks?.repository?.onChanged?.(repoPath, this.getFetchChanges(branch, options));
174
172
  }
173
+ if (fetched != null) this.followRemoteHeads(repoPath, fetched);
175
174
  }
176
175
  }
176
+ /**
177
+ * Writes the missing `refs/remotes/<remote>/HEAD` (the default branch the base reads) of each remote a fetch just
178
+ * read with its configured refspecs, once per remote, on git < 2.48 — newer git's fetch creates it itself. A bare
179
+ * fetch/pull reads every remote when `fetch.all` is set (git 2.44+), else its default remote. Right after the
180
+ * fetch, so the credentials it used are still cached. Never awaited; never rejects, failures not retried.
181
+ */
182
+ async followRemoteHeads(repoPath, fetched) {
183
+ try {
184
+ if (await this.git.supports("git:fetch:follow-remote-head")) return;
185
+ const commonPath = this.cache.getCommonPath(repoPath);
186
+ const pending = (names) => names.filter((r) => !this.followedRemoteHeads.has(`${commonPath}\0${r}`));
187
+ const config = await this.provider.config.getConfigRegex(repoPath, "^(fetch\\.all|remote\\..+\\.skipfetchall|branch\\..+\\.remote)$");
188
+ if (fetched === "default" && parseGitBoolean(config.get("fetch.all")) && await this.git.supports("git:fetch:all-config")) fetched = "all";
189
+ let remotes;
190
+ if (fetched === "all") remotes = pending((await this.provider.remotes.getRemotes(repoPath)).map((r) => r.name).filter((r) => !parseGitBoolean(config.get(`remote.${r}.skipfetchall`))));
191
+ else if (fetched === "default") {
192
+ const remote = await this.getDefaultFetchRemote(repoPath, config);
193
+ remotes = pending(remote != null ? [remote] : []);
194
+ } else remotes = pending([fetched.remote]);
195
+ if (!remotes.length) return;
196
+ for (const remote of remotes) this.followedRemoteHeads.add(`${commonPath}\0${remote}`);
197
+ for (const remote of remotes) try {
198
+ await this.provider.branches.setRemoteHeadIfMissing(repoPath, remote);
199
+ } catch {}
200
+ } catch {}
201
+ }
202
+ /**
203
+ * The remote a bare `fetch`/`pull` reads: the current branch's `branch.<name>.remote` (none for `.`, the local
204
+ * repository), else the sole remote, else `origin`
205
+ */
206
+ async getDefaultFetchRemote(repoPath, config) {
207
+ const current = await this.provider.branches.getBranch(repoPath);
208
+ const configured = current != null ? config.get(`branch.${current.name}.remote`) : void 0;
209
+ if (configured) return configured === "." ? void 0 : configured;
210
+ const remotes = await this.provider.remotes.getRemotes(repoPath);
211
+ return remotes.length === 1 ? remotes[0].name : "origin";
212
+ }
177
213
  /** `remotes`, plus `heads`/`tags` for any local branch or tag the fetch writes — a `pull` fetch writes `<upstream>:<branch>` */
178
214
  getFetchChanges(branch, options) {
179
215
  if (isBranchReference(branch)) return options?.pull ? ["heads", "remotes"] : ["remotes"];
@@ -234,18 +270,16 @@ var OperationsGitSubProvider = class {
234
270
  if (options?.noCommit) args.push("--no-commit");
235
271
  args.push(ref);
236
272
  try {
237
- await this.git.run({
238
- cwd: repoPath,
239
- errors: "throw",
240
- timeout: 0,
241
- ...runOptions
242
- }, ...args);
243
- this.context.hooks?.cache?.onReset?.(repoPath, "branches", "status");
244
- this.context.hooks?.repository?.onChanged?.(repoPath, [
245
- "head",
246
- "heads",
247
- "index"
248
- ]);
273
+ try {
274
+ await this.git.run({
275
+ cwd: repoPath,
276
+ errors: "throw",
277
+ timeout: 0,
278
+ ...runOptions
279
+ }, ...args);
280
+ } finally {
281
+ this.announceHeadChanged(repoPath);
282
+ }
249
283
  return { conflicted: false };
250
284
  } catch (ex) {
251
285
  scope?.error(ex);
@@ -265,6 +299,7 @@ var OperationsGitSubProvider = class {
265
299
  async pull(repoPath, options, runOptions) {
266
300
  const scope = getScopedLogger();
267
301
  let announce;
302
+ let fetched;
268
303
  try {
269
304
  if (isBranchReference(options?.branch)) {
270
305
  const branch = options.branch;
@@ -283,12 +318,15 @@ var OperationsGitSubProvider = class {
283
318
  tags: options?.tags,
284
319
  source: options?.source
285
320
  }, runOptions);
321
+ fetched = {
322
+ repoPath: worktreePath,
323
+ remotes: "default"
324
+ };
286
325
  } finally {
287
326
  this.context.hooks?.operations?.onRebaseCapableOperation?.(worktreePath, "pull", "ended");
288
327
  }
289
328
  } else if (options?.fastForward === "only") {
290
- const [branchName, remoteName] = getBranchNameAndRemote(branch);
291
- const upstream = getBranchTrackingWithoutRemote(branch);
329
+ const { name: branchName, remote: remoteName, upstream } = await resolveBranchRemote(this.provider, repoPath, branch, runOptions?.cancellation);
292
330
  if (remoteName == null || upstream == null) throw new PullError({
293
331
  reason: "noUpstream",
294
332
  gitCommand: {
@@ -331,6 +369,10 @@ var OperationsGitSubProvider = class {
331
369
  tags: options?.tags,
332
370
  source: options?.source
333
371
  }, runOptions);
372
+ fetched = {
373
+ repoPath,
374
+ remotes: "default"
375
+ };
334
376
  } finally {
335
377
  this.context.hooks?.operations?.onRebaseCapableOperation?.(repoPath, "pull", "ended");
336
378
  }
@@ -339,6 +381,7 @@ var OperationsGitSubProvider = class {
339
381
  throw ex;
340
382
  } finally {
341
383
  announce?.();
384
+ if (fetched != null) this.followRemoteHeads(fetched.repoPath, fetched.remotes);
342
385
  }
343
386
  }
344
387
  announcePull(repoPath) {
@@ -378,27 +421,34 @@ var OperationsGitSubProvider = class {
378
421
  let branchName;
379
422
  let remoteName;
380
423
  let upstreamName;
424
+ let trackUpstream = options?.publish != null;
381
425
  let setUpstream;
382
426
  if (isBranchReference(options?.reference)) {
427
+ const resolved = await resolveBranchRemote(this.provider, repoPath, options.reference, runOptions?.cancellation);
383
428
  if (options.publish != null) {
384
429
  branchName = options.reference.name;
385
430
  remoteName = options.publish.remote;
386
- } else [branchName, remoteName] = getBranchNameAndRemote(options.reference);
387
- upstreamName = getBranchTrackingWithoutRemote(options.reference);
431
+ } else {
432
+ branchName = resolved.name;
433
+ remoteName = resolved.remote;
434
+ }
435
+ upstreamName = resolved.upstream;
436
+ trackUpstream ||= options.reference.upstream?.missing === true;
388
437
  } else {
389
438
  const branch = await this.provider.branches.getBranch(repoPath);
390
439
  if (branch == null) return;
391
- if (options?.reference != null) branchName = `${options.reference.ref}:${options?.publish != null ? "refs/heads/" : ""}${branch.nameWithoutRemote}`;
440
+ const resolved = await resolveBranchRemote(this.provider, repoPath, branch, runOptions?.cancellation);
441
+ if (options?.reference != null) branchName = `${options.reference.ref}:${options?.publish != null ? "refs/heads/" : ""}${resolved.name}`;
392
442
  else {
393
- const tracking = options?.publish == null ? branch.trackingWithoutRemote : void 0;
394
- branchName = tracking != null && tracking !== branch.nameWithoutRemote ? `${branch.name}:${tracking}` : branch.name;
443
+ const tracking = options?.publish == null ? resolved.upstream : void 0;
444
+ branchName = tracking != null && tracking !== resolved.name ? `${branch.name}:${tracking}` : branch.name;
395
445
  }
396
- remoteName = branch.remoteName ?? options?.publish?.remote;
446
+ remoteName = resolved.remote ?? options?.publish?.remote;
397
447
  upstreamName = options?.reference == null && options?.publish != null ? branch.name : void 0;
398
448
  if (options?.publish?.remote != null && options?.reference != null) setUpstream = {
399
- branch: branch.nameWithoutRemote,
449
+ branch: resolved.name,
400
450
  remote: remoteName,
401
- remoteBranch: branch.nameWithoutRemote
451
+ remoteBranch: resolved.name
402
452
  };
403
453
  }
404
454
  if (options?.publish == null && remoteName == null && upstreamName == null) throw new PushError({ reason: "other" });
@@ -413,7 +463,7 @@ var OperationsGitSubProvider = class {
413
463
  remote: remoteName,
414
464
  upstream: upstreamName,
415
465
  force: forceOpts,
416
- publish: options?.publish != null
466
+ setUpstream: trackUpstream
417
467
  }, runOptions);
418
468
  if (setUpstream != null) try {
419
469
  await this.git.run({
@@ -428,11 +478,11 @@ var OperationsGitSubProvider = class {
428
478
  throw ex;
429
479
  } finally {
430
480
  this.context.hooks?.cache?.onReset?.(repoPath, "branches");
431
- this.context.hooks?.repository?.onChanged?.(repoPath, options?.publish != null ? [
432
- "config",
433
- "heads",
434
- "remotes"
435
- ] : ["remotes"]);
481
+ const changes = [];
482
+ if (trackUpstream || setUpstream != null) changes.push("config");
483
+ if (options?.publish != null) changes.push("heads");
484
+ changes.push("remotes");
485
+ this.context.hooks?.repository?.onChanged?.(repoPath, changes);
436
486
  }
437
487
  }
438
488
  async pushCore(repoPath, options, runOptions) {
@@ -446,8 +496,10 @@ var OperationsGitSubProvider = class {
446
496
  } else params.push("--force");
447
497
  }
448
498
  if (options.branch && options.remote) {
449
- if (options.upstream) params.push("-u", options.remote, `${options.branch}:${options.upstream}`);
450
- else if (options.publish) params.push("--set-upstream", options.remote, options.branch);
499
+ if (options.upstream) {
500
+ if (options.setUpstream) params.push("-u");
501
+ params.push(options.remote, `${options.branch}:${options.upstream}`);
502
+ } else if (options.setUpstream) params.push("--set-upstream", options.remote, options.branch);
451
503
  else params.push(options.remote, options.branch);
452
504
  } else if (options.remote) params.push(options.remote);
453
505
  else if (options.delete) params.push(options.delete.remote, `:${options.delete.branch}`);
@@ -528,20 +580,18 @@ var OperationsGitSubProvider = class {
528
580
  if (options?.branch) args.push(options.branch);
529
581
  this.context.hooks?.operations?.onRebaseCapableOperation?.(repoPath, "rebase", "started");
530
582
  try {
531
- await this.git.run({
532
- cwd: repoPath,
533
- errors: "throw",
534
- configs,
535
- timeout: 0,
536
- ...runOptions,
537
- env
538
- }, ...args);
539
- this.context.hooks?.cache?.onReset?.(repoPath, "branches", "status");
540
- this.context.hooks?.repository?.onChanged?.(repoPath, [
541
- "head",
542
- "heads",
543
- "index"
544
- ]);
583
+ try {
584
+ await this.git.run({
585
+ cwd: repoPath,
586
+ errors: "throw",
587
+ configs,
588
+ timeout: 0,
589
+ ...runOptions,
590
+ env
591
+ }, ...args);
592
+ } finally {
593
+ this.announceHeadChanged(repoPath);
594
+ }
545
595
  return { conflicted: false };
546
596
  } catch (ex) {
547
597
  scope?.error(ex);
@@ -564,15 +614,11 @@ var OperationsGitSubProvider = class {
564
614
  const scope = getScopedLogger();
565
615
  try {
566
616
  await this.resetCore(repoPath, rev, options?.mode, runOptions);
567
- this.context.hooks?.cache?.onReset?.(repoPath, "branches", "status");
568
- this.context.hooks?.repository?.onChanged?.(repoPath, [
569
- "head",
570
- "heads",
571
- "index"
572
- ]);
573
617
  } catch (ex) {
574
618
  scope?.error(ex);
575
619
  throw ex;
620
+ } finally {
621
+ this.announceHeadChanged(repoPath);
576
622
  }
577
623
  }
578
624
  async resetCore(repoPath, rev, mode, runOptions) {
@@ -606,11 +652,13 @@ var OperationsGitSubProvider = class {
606
652
  selector,
607
653
  "--"
608
654
  ] : ["checkout", "--"];
655
+ let ran = false;
609
656
  try {
610
657
  if (await this.git.supports("git:checkout:pathspec-from-file")) {
611
658
  const args = ["checkout"];
612
659
  if (selector != null) args.push(selector);
613
660
  args.push("--pathspec-from-file=-", "--pathspec-file-nul");
661
+ ran = true;
614
662
  await this.git.run({
615
663
  cwd: repoPath,
616
664
  errors: "throw",
@@ -620,14 +668,15 @@ var OperationsGitSubProvider = class {
620
668
  } else {
621
669
  const perArgOverhead = 3;
622
670
  const prefixLength = prefix.reduce((sum, arg) => sum + arg.length + perArgOverhead, 0);
623
- for (const batch of chunkByStringLength(normalized, maxGitCliLength - prefixLength, perArgOverhead)) await this.git.run({
624
- cwd: repoPath,
625
- errors: "throw",
626
- ...runOptions
627
- }, ...prefix, ...batch);
671
+ for (const batch of chunkByStringLength(normalized, maxGitCliLength - prefixLength, perArgOverhead)) {
672
+ ran = true;
673
+ await this.git.run({
674
+ cwd: repoPath,
675
+ errors: "throw",
676
+ ...runOptions
677
+ }, ...prefix, ...batch);
678
+ }
628
679
  }
629
- this.context.hooks?.cache?.onReset?.(repoPath, "status");
630
- this.context.hooks?.repository?.onChanged?.(repoPath, ["index"]);
631
680
  } catch (ex) {
632
681
  scope?.error(ex);
633
682
  throw getGitCommandError("checkout", ex, (reason) => new CheckoutError({
@@ -638,6 +687,11 @@ var OperationsGitSubProvider = class {
638
687
  args: [...prefix, ...normalized]
639
688
  }
640
689
  }, ex));
690
+ } finally {
691
+ if (ran) {
692
+ this.context.hooks?.cache?.onReset?.(repoPath, "status");
693
+ this.context.hooks?.repository?.onChanged?.(repoPath, ["index"]);
694
+ }
641
695
  }
642
696
  }
643
697
  async revert(repoPath, refs, options, runOptions) {
@@ -647,18 +701,16 @@ var OperationsGitSubProvider = class {
647
701
  else if (options?.editMessage === false) args.push("--no-edit");
648
702
  args.push(...refs);
649
703
  try {
650
- await this.git.run({
651
- cwd: repoPath,
652
- errors: "throw",
653
- timeout: 0,
654
- ...runOptions
655
- }, ...args);
656
- this.context.hooks?.cache?.onReset?.(repoPath, "branches", "status");
657
- this.context.hooks?.repository?.onChanged?.(repoPath, [
658
- "head",
659
- "heads",
660
- "index"
661
- ]);
704
+ try {
705
+ await this.git.run({
706
+ cwd: repoPath,
707
+ errors: "throw",
708
+ timeout: 0,
709
+ ...runOptions
710
+ }, ...args);
711
+ } finally {
712
+ this.announceHeadChanged(repoPath);
713
+ }
662
714
  return { conflicted: false };
663
715
  } catch (ex) {
664
716
  scope?.error(ex);
@@ -702,6 +754,21 @@ var OperationsGitSubProvider = class {
702
754
  }
703
755
  }, ex instanceof Error ? ex : void 0);
704
756
  }
757
+ /** Called once git has run, success or not — a rejected write can still have moved HEAD or left state behind */
758
+ announceHeadChanged(repoPath, wroteTracking) {
759
+ this.context.hooks?.cache?.onReset?.(repoPath, "branches", "status");
760
+ this.context.hooks?.repository?.onChanged?.(repoPath, wroteTracking ? [
761
+ "config",
762
+ "head",
763
+ "heads",
764
+ "index"
765
+ ] : [
766
+ "head",
767
+ "heads",
768
+ "index"
769
+ ]);
770
+ }
771
+ /** The caller has already announced the change — the conflict is what the failed run left behind */
705
772
  async createConflictResult(repoPath, command) {
706
773
  let conflicts;
707
774
  try {
@@ -709,12 +776,6 @@ var OperationsGitSubProvider = class {
709
776
  } catch (ex) {
710
777
  _logger.warn(`Unable to read conflicting files after ${command}: ${ex}`);
711
778
  }
712
- this.context.hooks?.cache?.onReset?.(repoPath, "branches", "status");
713
- this.context.hooks?.repository?.onChanged?.(repoPath, [
714
- "head",
715
- "heads",
716
- "index"
717
- ]);
718
779
  this.context.hooks?.operations?.onConflicted?.(command, conflicts);
719
780
  return {
720
781
  conflicted: true,