@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
@@ -1 +1 @@
1
- {"version":3,"file":"features.js","names":[],"sources":["../../../git/src/features.ts"],"sourcesContent":["// GitFeature's must start with `git:` to be recognized in all usages\nexport type GitFeatures =\n\t| 'git:checkout:pathspec-from-file'\n\t| 'git:commit-graph'\n\t| 'git:commit-graph:changed-paths'\n\t| 'git:fetch:no-write-fetch-head'\n\t| 'git:for-each-ref:worktreePath'\n\t| 'git:fsmonitor'\n\t| 'git:fsmonitor:linux'\n\t| 'git:ignoreRevsFile'\n\t| 'git:index:skipHash'\n\t| 'git:maintenance'\n\t| 'git:maintenance:pack-refs'\n\t| 'git:maintenance:start'\n\t| 'git:maintenance:start:systemd'\n\t| 'git:manyFiles'\n\t| 'git:merge-tree:merge-base'\n\t| 'git:merge-tree:write-tree'\n\t| 'git:patch-id:binary-oids'\n\t| 'git:patch-id:verbatim'\n\t| 'git:push:force-if-includes'\n\t| 'git:rebase:autosquash'\n\t| 'git:rev-parse:end-of-options'\n\t| 'git:signing:ssh'\n\t| 'git:signing:x509'\n\t| 'git:sparse-index'\n\t| 'git:stash:push:pathspecs'\n\t| 'git:stash:push:staged'\n\t| 'git:stash:push:stdin'\n\t| 'git:status:find-renames'\n\t| 'git:status:porcelain-v2'\n\t| 'git:untrackedCache'\n\t| 'git:worktrees';\n\ntype ExtractPrefix<T> = T extends `${infer Prefix}:${infer Rest}`\n\t? Rest extends `${infer SubPrefix}:${string}`\n\t\t? T | `${Prefix}:${SubPrefix}` | Prefix\n\t\t: T | Prefix\n\t: never;\n\nexport type GitFeatureOrPrefix = ExtractPrefix<GitFeatures>;\nexport type FilteredGitFeatures<T extends GitFeatureOrPrefix> = T extends GitFeatures\n\t? T\n\t: Extract<GitFeatures, T | `${T}:${string}`>;\n\nexport const gitMinimumVersion = '2.7.2';\nexport const gitFeaturesByVersion = new Map<GitFeatures, string>([\n\t['git:checkout:pathspec-from-file', '2.26'],\n\t// 2.24 is when git READS the commit-graph file by default (core.commitGraph on); writing it for\n\t// older gits would be dead weight.\n\t['git:commit-graph', '2.24'],\n\t// Changed-path Bloom filters (`--changed-paths`), the v2 filter format — pre-2.31 shipped Bloom filters\n\t// with real correctness bugs (bad results for merge commits), so 2.31 is the safe floor to write them.\n\t['git:commit-graph:changed-paths', '2.31'],\n\t['git:fetch:no-write-fetch-head', '2.29'],\n\t['git:for-each-ref:worktreePath', '2.23'],\n\t// `core.fsmonitor=true` selects the built-in FSMonitor daemon (accepting a bool rather than only a\n\t// hook path). This 2.37 floor is the Windows + macOS one.\n\t['git:fsmonitor', '2.37'],\n\t// Linux got its own FSMonitor backend (inotify) only in 2.55, hence a separate floor. Note the backend\n\t// places a watch on EVERY directory, so a large repo can exhaust `fs.inotify.max_user_watches` and the\n\t// daemon fails at runtime even on a new enough git — the apply path must still probe, not just gate.\n\t['git:fsmonitor:linux', '2.55'],\n\t['git:ignoreRevsFile', '2.23'],\n\t// `index.skipHash` (skip the trailing index checksum for faster writes); part of `feature.manyFiles`.\n\t['git:index:skipHash', '2.40'],\n\t// `git maintenance run --task=…`. The `maintenance` builtin + `commit-graph`/`gc` tasks are 2.29, but\n\t// the loose-objects + incremental-repack tasks the auto tier uses landed in 2.30 (and `core.multiPackIndex`\n\t// is default-on from 2.30, so no separate midx config write is needed) — 2.30 is the safe floor.\n\t['git:maintenance', '2.30'],\n\t// The pack-refs maintenance task landed one release after the maintenance builtin.\n\t['git:maintenance:pack-refs', '2.31'],\n\t// `git maintenance start` — the subcommands exist from 2.30 (cron only); launchctl (macOS) + schtasks\n\t// (Windows) scheduling arrived in 2.31, so 2.31 is the cross-platform-safe floor.\n\t['git:maintenance:start', '2.31'],\n\t// `git maintenance start` systemd-timer scheduling. On Linux, 2.31–2.33 is cron-only and modern distros\n\t// often ship without cron (scheduling then silently fails); the systemd fallback arrived in 2.34.\n\t['git:maintenance:start:systemd', '2.34'],\n\t// `feature.manyFiles` umbrella (index v4 + untracked cache + skipHash where available).\n\t['git:manyFiles', '2.24'],\n\t['git:merge-tree:merge-base', '2.40'],\n\t// `merge-tree --write-tree` mode with `-z`/`--name-only`/`--no-messages`; the older trivial mode can't check conflicts\n\t['git:merge-tree:write-tree', '2.38'],\n\t// `patch-id` hashes a binary change through its blob ids; older ones hash the diff's text, so need `--binary` data\n\t['git:patch-id:binary-oids', '2.39'],\n\t// `patch-id --verbatim`: hashes whitespace and file-mode header lines instead of normalizing them away\n\t['git:patch-id:verbatim', '2.39'],\n\t['git:push:force-if-includes', '2.30.0'],\n\t// `--autosquash` WITHOUT `-i` (folding `fixup!`/`squash!` commits into a plain/automatic rebase).\n\t// Interactive rebases support autosquash on every git version GitLens supports, so this floor only\n\t// gates the non-interactive path.\n\t['git:rebase:autosquash', '2.44'],\n\t['git:rev-parse:end-of-options', '2.30'],\n\t['git:signing:ssh', '2.34.0'],\n\t['git:signing:x509', '2.19.0'],\n\t// Sparse-index support debuted earlier, but 2.33 shipped a corruption fix and 2.34 broadened command\n\t// support. Use 2.34 as the conservative floor before offering a repository mutation.\n\t['git:sparse-index', '2.34'],\n\t['git:stash:push:pathspecs', '2.13.2'],\n\t['git:stash:push:staged', '2.35.0'],\n\t['git:stash:push:stdin', '2.30.0'],\n\t['git:status:find-renames', '2.18'],\n\t['git:status:porcelain-v2', '2.11'],\n\t// `core.untrackedCache=true` (repo-local cache of untracked-file scans — the auto-tier config lever).\n\t['git:untrackedCache', '2.8'],\n\t['git:worktrees', '2.17.0'],\n]);\n"],"mappings":";AA6CA,MAAa,oBAAoB;AACjC,MAAa,uCAAuB,IAAI,IAAyB;CAChE,CAAC,mCAAmC,MAAM;CAG1C,CAAC,oBAAoB,MAAM;CAG3B,CAAC,kCAAkC,MAAM;CACzC,CAAC,iCAAiC,MAAM;CACxC,CAAC,iCAAiC,MAAM;CAGxC,CAAC,iBAAiB,MAAM;CAIxB,CAAC,uBAAuB,MAAM;CAC9B,CAAC,sBAAsB,MAAM;CAE7B,CAAC,sBAAsB,MAAM;CAI7B,CAAC,mBAAmB,MAAM;CAE1B,CAAC,6BAA6B,MAAM;CAGpC,CAAC,yBAAyB,MAAM;CAGhC,CAAC,iCAAiC,MAAM;CAExC,CAAC,iBAAiB,MAAM;CACxB,CAAC,6BAA6B,MAAM;CAEpC,CAAC,6BAA6B,MAAM;CAEpC,CAAC,4BAA4B,MAAM;CAEnC,CAAC,yBAAyB,MAAM;CAChC,CAAC,8BAA8B,QAAQ;CAIvC,CAAC,yBAAyB,MAAM;CAChC,CAAC,gCAAgC,MAAM;CACvC,CAAC,mBAAmB,QAAQ;CAC5B,CAAC,oBAAoB,QAAQ;CAG7B,CAAC,oBAAoB,MAAM;CAC3B,CAAC,4BAA4B,QAAQ;CACrC,CAAC,yBAAyB,QAAQ;CAClC,CAAC,wBAAwB,QAAQ;CACjC,CAAC,2BAA2B,MAAM;CAClC,CAAC,2BAA2B,MAAM;CAElC,CAAC,sBAAsB,KAAK;CAC5B,CAAC,iBAAiB,QAAQ;AAC3B,CAAC"}
1
+ {"version":3,"file":"features.js","names":[],"sources":["../../../git/src/features.ts"],"sourcesContent":["// GitFeature's must start with `git:` to be recognized in all usages\nexport type GitFeatures =\n\t| 'git:checkout:pathspec-from-file'\n\t| 'git:commit-graph'\n\t| 'git:commit-graph:changed-paths'\n\t| 'git:fetch:all-config'\n\t| 'git:fetch:follow-remote-head'\n\t| 'git:fetch:no-write-fetch-head'\n\t| 'git:for-each-ref:ahead-behind'\n\t| 'git:for-each-ref:worktreePath'\n\t| 'git:fsmonitor'\n\t| 'git:fsmonitor:linux'\n\t| 'git:ignoreRevsFile'\n\t| 'git:index:skipHash'\n\t| 'git:maintenance'\n\t| 'git:maintenance:pack-refs'\n\t| 'git:maintenance:start'\n\t| 'git:maintenance:start:systemd'\n\t| 'git:manyFiles'\n\t| 'git:merge-tree:merge-base'\n\t| 'git:merge-tree:write-tree'\n\t| 'git:patch-id:binary-oids'\n\t| 'git:patch-id:verbatim'\n\t| 'git:push:force-if-includes'\n\t| 'git:rebase:autosquash'\n\t| 'git:rev-parse:end-of-options'\n\t| 'git:signing:ssh'\n\t| 'git:signing:x509'\n\t| 'git:sparse-index'\n\t| 'git:stash:push:pathspecs'\n\t| 'git:stash:push:staged'\n\t| 'git:stash:push:stdin'\n\t| 'git:status:find-renames'\n\t| 'git:status:ignored-matching'\n\t| 'git:status:porcelain-v2'\n\t| 'git:untrackedCache'\n\t| 'git:worktree:list:lock-reason'\n\t| 'git:worktrees';\n\ntype ExtractPrefix<T> = T extends `${infer Prefix}:${infer Rest}`\n\t? Rest extends `${infer SubPrefix}:${string}`\n\t\t? T | `${Prefix}:${SubPrefix}` | Prefix\n\t\t: T | Prefix\n\t: never;\n\nexport type GitFeatureOrPrefix = ExtractPrefix<GitFeatures>;\nexport type FilteredGitFeatures<T extends GitFeatureOrPrefix> = T extends GitFeatures\n\t? T\n\t: Extract<GitFeatures, T | `${T}:${string}`>;\n\nexport const gitMinimumVersion = '2.7.2';\nexport const gitFeaturesByVersion = new Map<GitFeatures, string>([\n\t['git:checkout:pathspec-from-file', '2.26'],\n\t// 2.24 is when git READS the commit-graph file by default (core.commitGraph on); writing it for\n\t// older gits would be dead weight.\n\t['git:commit-graph', '2.24'],\n\t// Changed-path Bloom filters (`--changed-paths`), the v2 filter format — pre-2.31 shipped Bloom filters\n\t// with real correctness bugs (bad results for merge commits), so 2.31 is the safe floor to write them.\n\t['git:commit-graph:changed-paths', '2.31'],\n\t// A bare `fetch` reads every remote when `fetch.all` is set\n\t['git:fetch:all-config', '2.44'],\n\t// A fetch using a remote's configured refspecs creates its missing `refs/remotes/<remote>/HEAD`\n\t// (`remote.<name>.followRemoteHEAD`, default `create`)\n\t['git:fetch:follow-remote-head', '2.48'],\n\t['git:fetch:no-write-fetch-head', '2.29'],\n\t// `%(ahead-behind:<commit>)` in for-each-ref formats\n\t['git:for-each-ref:ahead-behind', '2.41'],\n\t['git:for-each-ref:worktreePath', '2.23'],\n\t// `core.fsmonitor=true` selects the built-in FSMonitor daemon (accepting a bool rather than only a\n\t// hook path). This 2.37 floor is the Windows + macOS one.\n\t['git:fsmonitor', '2.37'],\n\t// Linux got its own FSMonitor backend (inotify) only in 2.55, hence a separate floor. Note the backend\n\t// places a watch on EVERY directory, so a large repo can exhaust `fs.inotify.max_user_watches` and the\n\t// daemon fails at runtime even on a new enough git — the apply path must still probe, not just gate.\n\t['git:fsmonitor:linux', '2.55'],\n\t['git:ignoreRevsFile', '2.23'],\n\t// `index.skipHash` (skip the trailing index checksum for faster writes); part of `feature.manyFiles`.\n\t['git:index:skipHash', '2.40'],\n\t// `git maintenance run --task=…`. The `maintenance` builtin + `commit-graph`/`gc` tasks are 2.29, but\n\t// the loose-objects + incremental-repack tasks the auto tier uses landed in 2.30 (and `core.multiPackIndex`\n\t// is default-on from 2.30, so no separate midx config write is needed) — 2.30 is the safe floor.\n\t['git:maintenance', '2.30'],\n\t// The pack-refs maintenance task landed one release after the maintenance builtin.\n\t['git:maintenance:pack-refs', '2.31'],\n\t// `git maintenance start` — the subcommands exist from 2.30 (cron only); launchctl (macOS) + schtasks\n\t// (Windows) scheduling arrived in 2.31, so 2.31 is the cross-platform-safe floor.\n\t['git:maintenance:start', '2.31'],\n\t// `git maintenance start` systemd-timer scheduling. On Linux, 2.31–2.33 is cron-only and modern distros\n\t// often ship without cron (scheduling then silently fails); the systemd fallback arrived in 2.34.\n\t['git:maintenance:start:systemd', '2.34'],\n\t// `feature.manyFiles` umbrella (index v4 + untracked cache + skipHash where available).\n\t['git:manyFiles', '2.24'],\n\t['git:merge-tree:merge-base', '2.40'],\n\t// `merge-tree --write-tree` mode with `-z`/`--name-only`/`--no-messages`; the older trivial mode can't check conflicts\n\t['git:merge-tree:write-tree', '2.38'],\n\t// `patch-id` hashes a binary change through its blob ids; older ones hash the diff's text, so need `--binary` data\n\t['git:patch-id:binary-oids', '2.39'],\n\t// `patch-id --verbatim`: hashes whitespace and file-mode header lines instead of normalizing them away\n\t['git:patch-id:verbatim', '2.39'],\n\t['git:push:force-if-includes', '2.30.0'],\n\t// `--autosquash` WITHOUT `-i` (folding `fixup!`/`squash!` commits into a plain/automatic rebase).\n\t// Interactive rebases support autosquash on every git version GitLens supports, so this floor only\n\t// gates the non-interactive path.\n\t['git:rebase:autosquash', '2.44'],\n\t['git:rev-parse:end-of-options', '2.30'],\n\t['git:signing:ssh', '2.34.0'],\n\t['git:signing:x509', '2.19.0'],\n\t// Sparse-index support debuted earlier, but 2.33 shipped a corruption fix and 2.34 broadened command\n\t// support. Use 2.34 as the conservative floor before offering a repository mutation.\n\t['git:sparse-index', '2.34'],\n\t['git:stash:push:pathspecs', '2.13.2'],\n\t['git:stash:push:staged', '2.35.0'],\n\t['git:stash:push:stdin', '2.30.0'],\n\t['git:status:find-renames', '2.18'],\n\t// `status --ignored=matching`: an ignored folder is one entry, without a walk of what is inside it\n\t['git:status:ignored-matching', '2.16'],\n\t['git:status:porcelain-v2', '2.11'],\n\t// `core.untrackedCache=true` (repo-local cache of untracked-file scans — the auto-tier config lever).\n\t['git:untrackedCache', '2.8'],\n\t// `worktree list --porcelain` prints a lock's reason (`locked <reason>`); older ones print a bare `locked`\n\t['git:worktree:list:lock-reason', '2.31'],\n\t['git:worktrees', '2.17.0'],\n]);\n"],"mappings":";AAkDA,MAAa,oBAAoB;AACjC,MAAa,uCAAuB,IAAI,IAAyB;CAChE,CAAC,mCAAmC,MAAM;CAG1C,CAAC,oBAAoB,MAAM;CAG3B,CAAC,kCAAkC,MAAM;CAEzC,CAAC,wBAAwB,MAAM;CAG/B,CAAC,gCAAgC,MAAM;CACvC,CAAC,iCAAiC,MAAM;CAExC,CAAC,iCAAiC,MAAM;CACxC,CAAC,iCAAiC,MAAM;CAGxC,CAAC,iBAAiB,MAAM;CAIxB,CAAC,uBAAuB,MAAM;CAC9B,CAAC,sBAAsB,MAAM;CAE7B,CAAC,sBAAsB,MAAM;CAI7B,CAAC,mBAAmB,MAAM;CAE1B,CAAC,6BAA6B,MAAM;CAGpC,CAAC,yBAAyB,MAAM;CAGhC,CAAC,iCAAiC,MAAM;CAExC,CAAC,iBAAiB,MAAM;CACxB,CAAC,6BAA6B,MAAM;CAEpC,CAAC,6BAA6B,MAAM;CAEpC,CAAC,4BAA4B,MAAM;CAEnC,CAAC,yBAAyB,MAAM;CAChC,CAAC,8BAA8B,QAAQ;CAIvC,CAAC,yBAAyB,MAAM;CAChC,CAAC,gCAAgC,MAAM;CACvC,CAAC,mBAAmB,QAAQ;CAC5B,CAAC,oBAAoB,QAAQ;CAG7B,CAAC,oBAAoB,MAAM;CAC3B,CAAC,4BAA4B,QAAQ;CACrC,CAAC,yBAAyB,QAAQ;CAClC,CAAC,wBAAwB,QAAQ;CACjC,CAAC,2BAA2B,MAAM;CAElC,CAAC,+BAA+B,MAAM;CACtC,CAAC,2BAA2B,MAAM;CAElC,CAAC,sBAAsB,KAAK;CAE5B,CAAC,iCAAiC,MAAM;CACxC,CAAC,iBAAiB,QAAQ;AAC3B,CAAC"}
@@ -3,6 +3,12 @@ import { Shape } from "../../utils/types.js";
3
3
  import { GitBranchReference } from "./reference.js";
4
4
  //#region ../git/src/models/branch.d.ts
5
5
  export type BranchDisposition = 'starred' | 'archived';
6
+ /** The `.git/gk/config` keys (`branch.<name>.<key>`) a branch's {@link BranchMetadata} is read from */
7
+ export type BranchMetadataGkConfigKey = 'gk-last-accessed' | 'gk-last-modified' | 'gk-agent-last-activity' | 'gk-disposition';
8
+ /**
9
+ * A branch's `.git/gk/config` metadata. Unlike other cached values, the cache updates these objects in place when a
10
+ * key changes (see `Cache.patchBranchMetadata`), so every `GitBranch` holding one, old or new, reads the new value
11
+ */
6
12
  export interface BranchMetadata {
7
13
  lastAccessedAt?: string;
8
14
  lastModifiedAt?: string;
@@ -15,7 +21,10 @@ export declare class GitBranch implements GitBranchReference {
15
21
  readonly refName: string;
16
22
  readonly current: boolean;
17
23
  readonly date: Date | undefined;
18
- /** GK config metadata (dates, disposition) */
24
+ /**
25
+ * GK config metadata (dates, disposition), shared with the cache and updated in place: comparing an old and a
26
+ * new branch can't detect a changed stamp (no change event fires for one either)
27
+ */
19
28
  readonly metadata: BranchMetadata | undefined;
20
29
  readonly sha?: string | undefined;
21
30
  readonly upstream?: GitTrackingUpstream | undefined;
@@ -32,7 +41,10 @@ export declare class GitBranch implements GitBranchReference {
32
41
  private readonly _remote;
33
42
  get remote(): boolean;
34
43
  constructor(repoPath: string, refName: string, current: boolean, date: Date | undefined,
35
- /** GK config metadata (dates, disposition) */
44
+ /**
45
+ * GK config metadata (dates, disposition), shared with the cache and updated in place: comparing an old and a
46
+ * new branch can't detect a changed stamp (no change event fires for one either)
47
+ */
36
48
  metadata: BranchMetadata | undefined, sha?: string | undefined, upstream?: GitTrackingUpstream | undefined, worktree?: {
37
49
  path: string;
38
50
  isDefault: boolean;
@@ -43,6 +55,7 @@ export declare class GitBranch implements GitBranchReference {
43
55
  /** @returns The most recent date among lastModifiedDate, lastAccessedDate, and branch.date */
44
56
  get effectiveDate(): Date | undefined;
45
57
  get lastAccessedDate(): Date | undefined;
58
+ /** When a checkout's working tree or index last changed while on this branch (`gk-last-modified`), not only commits */
46
59
  get lastModifiedDate(): Date | undefined;
47
60
  get nameWithoutRemote(): string;
48
61
  get ref(): string;
@@ -75,6 +88,11 @@ export interface GitTrackingState {
75
88
  }
76
89
  export interface GitTrackingUpstream {
77
90
  readonly name: string;
91
+ /**
92
+ * The remote the upstream is on (`branch.<name>.remote`) as git reports it, so a remote whose own name contains a
93
+ * `/` stays whole. `undefined` when git is too old to report it (before 2.23 here) or the upstream is a local branch
94
+ */
95
+ readonly remote?: string;
78
96
  readonly missing: boolean;
79
97
  readonly state: GitTrackingState;
80
98
  }
@@ -1,13 +1,36 @@
1
1
  import { loggable } from "../../utils/decorators/log.js";
2
2
  import { memoize } from "../../utils/decorators/memoize.js";
3
3
  import { getBranchId, getRemoteNameFromBranchName, getRemoteNameSlashIndex } from "../../utils/gitRefs.js";
4
+ import { formatDetachedHeadName, getBranchTrackingWithoutRemote, isDetachedHead, parseRefName } from "../utils/branch.utils.js";
4
5
  import __decorate from "../../_virtual/@oxc-project+runtime/helpers/esm/decorate.js";
5
6
  import { formatDate, fromNow } from "../../utils/date.js";
6
7
  import { serializable } from "../../utils/decorators/serializable.js";
7
- import { formatDetachedHeadName, getBranchTrackingWithoutRemote, isDetachedHead, parseRefName } from "../utils/branch.utils.js";
8
8
  import { getUpstreamStatus } from "../utils/status.utils.js";
9
9
  //#region ../git/src/models/branch.ts
10
10
  var _GitBranch;
11
+ /**
12
+ * Each metadata object's last parsed stamps. Not `@memoize`d on the branch: the cache updates `BranchMetadata` in
13
+ * place, so a parse is reused only while its stamp is unchanged — and shared by every branch holding the object.
14
+ */
15
+ const stampDates = /* @__PURE__ */ new WeakMap();
16
+ function getStampDate(metadata, field) {
17
+ const stamp = metadata[field];
18
+ if (!stamp) return void 0;
19
+ let parsed = stampDates.get(metadata);
20
+ if (parsed == null) {
21
+ parsed = {};
22
+ stampDates.set(metadata, parsed);
23
+ }
24
+ let entry = parsed[field];
25
+ if (entry?.stamp !== stamp) {
26
+ entry = {
27
+ stamp,
28
+ date: new Date(stamp)
29
+ };
30
+ parsed[field] = entry;
31
+ }
32
+ return entry.date;
33
+ }
11
34
  let GitBranch = _GitBranch = class GitBranch {
12
35
  repoPath;
13
36
  refName;
@@ -70,10 +93,11 @@ let GitBranch = _GitBranch = class GitBranch {
70
93
  return maxTime != null ? new Date(maxTime) : void 0;
71
94
  }
72
95
  get lastAccessedDate() {
73
- return this.metadata?.lastAccessedAt ? new Date(this.metadata.lastAccessedAt) : void 0;
96
+ return this.metadata != null ? getStampDate(this.metadata, "lastAccessedAt") : void 0;
74
97
  }
98
+ /** When a checkout's working tree or index last changed while on this branch (`gk-last-modified`), not only commits */
75
99
  get lastModifiedDate() {
76
- return this.metadata?.lastModifiedAt ? new Date(this.metadata.lastModifiedAt) : void 0;
100
+ return this.metadata != null ? getStampDate(this.metadata, "lastModifiedAt") : void 0;
77
101
  }
78
102
  get nameWithoutRemote() {
79
103
  return this.remote ? this.name.substring(getRemoteNameSlashIndex(this.name) + 1) : this.name;
@@ -83,7 +107,7 @@ let GitBranch = _GitBranch = class GitBranch {
83
107
  }
84
108
  get remoteName() {
85
109
  if (this.remote) return getRemoteNameFromBranchName(this.name);
86
- if (this.upstream != null) return getRemoteNameFromBranchName(this.upstream.name);
110
+ if (this.upstream != null) return this.upstream.remote ?? getRemoteNameFromBranchName(this.upstream.name);
87
111
  }
88
112
  get starred() {
89
113
  return this.metadata?.disposition === "starred";
@@ -123,8 +147,6 @@ let GitBranch = _GitBranch = class GitBranch {
123
147
  }
124
148
  };
125
149
  __decorate([memoize()], GitBranch.prototype, "basename", null);
126
- __decorate([memoize()], GitBranch.prototype, "lastAccessedDate", null);
127
- __decorate([memoize()], GitBranch.prototype, "lastModifiedDate", null);
128
150
  __decorate([memoize()], GitBranch.prototype, "nameWithoutRemote", null);
129
151
  __decorate([memoize()], GitBranch.prototype, "remoteName", null);
130
152
  __decorate([memoize()], GitBranch.prototype, "trackingWithoutRemote", null);
@@ -1 +1 @@
1
- {"version":3,"file":"branch.js","names":[],"sources":["../../../../git/src/models/branch.ts"],"sourcesContent":["import { formatDate, fromNow } from '@gitlens/utils/date.js';\nimport { loggable } from '@gitlens/utils/decorators/log.js';\nimport { memoize } from '@gitlens/utils/decorators/memoize.js';\nimport { serializable } from '@gitlens/utils/decorators/serializable.js';\nimport { getBranchId, getRemoteNameFromBranchName, getRemoteNameSlashIndex } from '@gitlens/utils/gitRefs.js';\nimport type { MaybePausedResult } from '@gitlens/utils/promise.js';\nimport type { Shape } from '@gitlens/utils/types.js';\nimport {\n\tformatDetachedHeadName,\n\tgetBranchTrackingWithoutRemote,\n\tisDetachedHead,\n\tparseRefName,\n} from '../utils/branch.utils.js';\nimport { getUpstreamStatus } from '../utils/status.utils.js';\nimport type { GitBranchReference } from './reference.js';\n\nexport type BranchDisposition = 'starred' | 'archived';\n\nexport interface BranchMetadata {\n\tlastAccessedAt?: string;\n\tlastModifiedAt?: string;\n\tagentLastActivityAt?: string;\n\tdisposition?: BranchDisposition;\n}\n\nexport type GitBranchShape = Shape<GitBranch>;\n\n@loggable(i => i.id)\n@serializable\nexport class GitBranch implements GitBranchReference {\n\treadonly refType = 'branch';\n\treadonly detached: boolean;\n\treadonly id: string;\n\n\tprivate readonly _name: string;\n\tget name(): string {\n\t\treturn this._name;\n\t}\n\n\tprivate readonly _remote: boolean;\n\tget remote(): boolean {\n\t\treturn this._remote;\n\t}\n\n\tconstructor(\n\t\tpublic readonly repoPath: string,\n\t\tpublic readonly refName: string,\n\t\tpublic readonly current: boolean,\n\t\tpublic readonly date: Date | undefined,\n\t\t/** GK config metadata (dates, disposition) */\n\t\tpublic readonly metadata: BranchMetadata | undefined,\n\t\tpublic readonly sha?: string,\n\t\tpublic readonly upstream?: GitTrackingUpstream,\n\t\tpublic readonly worktree?: { path: string; isDefault: boolean } | false,\n\t\tdetached: boolean = false,\n\t\tpublic readonly rebasing: boolean = false,\n\t) {\n\t\t({ name: this._name, remote: this._remote } = parseRefName(refName));\n\n\t\tthis.detached = detached || (this.current ? isDetachedHead(this._name) : false);\n\t\tif (this.detached) {\n\t\t\tthis.id = getBranchId(repoPath, this._remote, this.sha!);\n\t\t\tthis._name = formatDetachedHeadName(this.sha!);\n\t\t} else {\n\t\t\tthis.id = getBranchId(repoPath, this._remote, this._name);\n\t\t}\n\n\t\tthis.upstream = upstream?.name ? upstream : undefined;\n\t}\n\n\tget archived(): boolean {\n\t\treturn this.metadata?.disposition === 'archived';\n\t}\n\n\t@memoize()\n\tget basename(): string {\n\t\tconst name = this.nameWithoutRemote;\n\t\tconst index = name.lastIndexOf('/');\n\t\treturn index !== -1 ? name.substring(index + 1) : name;\n\t}\n\n\tget disposition(): BranchDisposition | undefined {\n\t\treturn this.metadata?.disposition;\n\t}\n\n\t/** @returns The most recent date among lastModifiedDate, lastAccessedDate, and branch.date */\n\tget effectiveDate(): Date | undefined {\n\t\tlet maxTime: number | undefined;\n\n\t\tconst accessed = this.lastAccessedDate?.getTime();\n\t\tif (accessed != null && (maxTime == null || accessed > maxTime)) {\n\t\t\tmaxTime = accessed;\n\t\t}\n\n\t\tconst modified = this.lastModifiedDate?.getTime();\n\t\tif (modified != null && (maxTime == null || modified > maxTime)) {\n\t\t\tmaxTime = modified;\n\t\t}\n\n\t\tconst date = this.date?.getTime();\n\t\tif (date != null && (maxTime == null || date > maxTime)) {\n\t\t\tmaxTime = date;\n\t\t}\n\n\t\treturn maxTime != null ? new Date(maxTime) : undefined;\n\t}\n\n\t@memoize()\n\tget lastAccessedDate(): Date | undefined {\n\t\treturn this.metadata?.lastAccessedAt ? new Date(this.metadata.lastAccessedAt) : undefined;\n\t}\n\n\t@memoize()\n\tget lastModifiedDate(): Date | undefined {\n\t\treturn this.metadata?.lastModifiedAt ? new Date(this.metadata.lastModifiedAt) : undefined;\n\t}\n\n\t@memoize()\n\tget nameWithoutRemote(): string {\n\t\treturn this.remote ? this.name.substring(getRemoteNameSlashIndex(this.name) + 1) : this.name;\n\t}\n\n\tget ref(): string {\n\t\treturn this.detached ? this.sha! : this._name;\n\t}\n\n\t@memoize()\n\tget remoteName(): string | undefined {\n\t\tif (this.remote) return getRemoteNameFromBranchName(this.name);\n\t\tif (this.upstream != null) return getRemoteNameFromBranchName(this.upstream.name);\n\n\t\treturn undefined;\n\t}\n\n\tget starred(): boolean {\n\t\treturn this.metadata?.disposition === 'starred';\n\t}\n\n\tget status(): GitBranchStatus {\n\t\tif (this.remote) return 'remote';\n\t\tif (this.upstream == null) return this.detached ? 'detached' : 'local';\n\n\t\tif (this.upstream.missing) return 'missingUpstream';\n\t\tif (this.upstream.state.ahead && this.upstream.state.behind) return 'diverged';\n\t\tif (this.upstream.state.ahead) return 'ahead';\n\t\tif (this.upstream.state.behind) return 'behind';\n\t\treturn 'upToDate';\n\t}\n\n\t@memoize()\n\tget trackingWithoutRemote(): string | undefined {\n\t\treturn getBranchTrackingWithoutRemote(this);\n\t}\n\n\t/** Creates a copy of this branch with a different repoPath and optionally a different current flag — ONLY used for worktree-aware caching */\n\twithRepoPath(repoPath: string, current?: boolean): GitBranch {\n\t\tconst newCurrent = current ?? this.current;\n\t\tif (repoPath === this.repoPath && newCurrent === this.current) return this;\n\t\treturn new GitBranch(\n\t\t\trepoPath,\n\t\t\tthis.refName,\n\t\t\tnewCurrent,\n\t\t\tthis.date,\n\t\t\tthis.metadata,\n\t\t\tthis.sha,\n\t\t\tthis.upstream,\n\t\t\tthis.worktree,\n\t\t\tthis.detached,\n\t\t\tthis.rebasing,\n\t\t);\n\t}\n\n\tstatic is(branch: unknown): branch is GitBranch {\n\t\treturn branch instanceof GitBranch;\n\t}\n\n\tstatic formatDate(branch: GitBranchShape, format?: string | null): string {\n\t\treturn branch.date != null ? formatDate(branch.date, format ?? 'MMMM Do, YYYY h:mma') : '';\n\t}\n\n\tstatic formatDateFromNow(branch: GitBranchShape): string {\n\t\treturn branch.date != null ? fromNow(branch.date) : '';\n\t}\n\n\tstatic formatDateWithStyle(\n\t\tbranch: GitBranchShape,\n\t\tformatting: { dateStyle: string; dateFormat: string | null },\n\t): string {\n\t\treturn formatting.dateStyle === 'absolute'\n\t\t\t? GitBranch.formatDate(branch, formatting.dateFormat)\n\t\t\t: GitBranch.formatDateFromNow(branch);\n\t}\n\n\tstatic getTrackingStatus(\n\t\tbranch: GitBranchShape,\n\t\toptions?: {\n\t\t\tcount?: boolean;\n\t\t\tempty?: string;\n\t\t\texpand?: boolean;\n\t\t\ticons?: boolean;\n\t\t\tprefix?: string;\n\t\t\tseparator?: string;\n\t\t\tsuffix?: string;\n\t\t},\n\t): string {\n\t\treturn getUpstreamStatus(branch.upstream, options);\n\t}\n}\n\nexport interface GitTrackingState {\n\treadonly ahead: number;\n\treadonly behind: number;\n}\n\nexport interface GitTrackingUpstream {\n\treadonly name: string;\n\treadonly missing: boolean;\n\treadonly state: GitTrackingState;\n}\n\nexport type GitBranchStatus =\n\t| 'local'\n\t| 'detached'\n\t| 'ahead'\n\t| 'behind'\n\t| 'diverged'\n\t| 'upToDate'\n\t| 'missingUpstream'\n\t| 'remote';\n\nexport interface BranchTargetInfo {\n\tmergeTargetBranch: MaybePausedResult<string | undefined>;\n\tbaseBranch: string | undefined;\n\tdefaultBranch: string | undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"branch.js","names":[],"sources":["../../../../git/src/models/branch.ts"],"sourcesContent":["import { formatDate, fromNow } from '@gitlens/utils/date.js';\nimport { loggable } from '@gitlens/utils/decorators/log.js';\nimport { memoize } from '@gitlens/utils/decorators/memoize.js';\nimport { serializable } from '@gitlens/utils/decorators/serializable.js';\nimport { getBranchId, getRemoteNameFromBranchName, getRemoteNameSlashIndex } from '@gitlens/utils/gitRefs.js';\nimport type { MaybePausedResult } from '@gitlens/utils/promise.js';\nimport type { Shape } from '@gitlens/utils/types.js';\nimport {\n\tformatDetachedHeadName,\n\tgetBranchTrackingWithoutRemote,\n\tisDetachedHead,\n\tparseRefName,\n} from '../utils/branch.utils.js';\nimport { getUpstreamStatus } from '../utils/status.utils.js';\nimport type { GitBranchReference } from './reference.js';\n\nexport type BranchDisposition = 'starred' | 'archived';\n\n/** The `.git/gk/config` keys (`branch.<name>.<key>`) a branch's {@link BranchMetadata} is read from */\nexport type BranchMetadataGkConfigKey =\n\t| 'gk-last-accessed'\n\t| 'gk-last-modified'\n\t| 'gk-agent-last-activity'\n\t| 'gk-disposition';\n\n/**\n * A branch's `.git/gk/config` metadata. Unlike other cached values, the cache updates these objects in place when a\n * key changes (see `Cache.patchBranchMetadata`), so every `GitBranch` holding one, old or new, reads the new value\n */\nexport interface BranchMetadata {\n\tlastAccessedAt?: string;\n\tlastModifiedAt?: string;\n\tagentLastActivityAt?: string;\n\tdisposition?: BranchDisposition;\n}\n\nexport type GitBranchShape = Shape<GitBranch>;\n\n/**\n * Each metadata object's last parsed stamps. Not `@memoize`d on the branch: the cache updates `BranchMetadata` in\n * place, so a parse is reused only while its stamp is unchanged — and shared by every branch holding the object.\n */\nconst stampDates = new WeakMap<BranchMetadata, Partial<Record<StampField, { stamp: string; date: Date }>>>();\ntype StampField = 'lastAccessedAt' | 'lastModifiedAt';\n\nfunction getStampDate(metadata: BranchMetadata, field: StampField): Date | undefined {\n\tconst stamp = metadata[field];\n\tif (!stamp) return undefined;\n\n\tlet parsed = stampDates.get(metadata);\n\tif (parsed == null) {\n\t\tparsed = {};\n\t\tstampDates.set(metadata, parsed);\n\t}\n\n\tlet entry = parsed[field];\n\tif (entry?.stamp !== stamp) {\n\t\tentry = { stamp: stamp, date: new Date(stamp) };\n\t\tparsed[field] = entry;\n\t}\n\treturn entry.date;\n}\n\n@loggable(i => i.id)\n@serializable\nexport class GitBranch implements GitBranchReference {\n\treadonly refType = 'branch';\n\treadonly detached: boolean;\n\treadonly id: string;\n\n\tprivate readonly _name: string;\n\tget name(): string {\n\t\treturn this._name;\n\t}\n\n\tprivate readonly _remote: boolean;\n\tget remote(): boolean {\n\t\treturn this._remote;\n\t}\n\n\tconstructor(\n\t\tpublic readonly repoPath: string,\n\t\tpublic readonly refName: string,\n\t\tpublic readonly current: boolean,\n\t\tpublic readonly date: Date | undefined,\n\t\t/**\n\t\t * GK config metadata (dates, disposition), shared with the cache and updated in place: comparing an old and a\n\t\t * new branch can't detect a changed stamp (no change event fires for one either)\n\t\t */\n\t\tpublic readonly metadata: BranchMetadata | undefined,\n\t\tpublic readonly sha?: string,\n\t\tpublic readonly upstream?: GitTrackingUpstream,\n\t\tpublic readonly worktree?: { path: string; isDefault: boolean } | false,\n\t\tdetached: boolean = false,\n\t\tpublic readonly rebasing: boolean = false,\n\t) {\n\t\t({ name: this._name, remote: this._remote } = parseRefName(refName));\n\n\t\tthis.detached = detached || (this.current ? isDetachedHead(this._name) : false);\n\t\tif (this.detached) {\n\t\t\tthis.id = getBranchId(repoPath, this._remote, this.sha!);\n\t\t\tthis._name = formatDetachedHeadName(this.sha!);\n\t\t} else {\n\t\t\tthis.id = getBranchId(repoPath, this._remote, this._name);\n\t\t}\n\n\t\tthis.upstream = upstream?.name ? upstream : undefined;\n\t}\n\n\tget archived(): boolean {\n\t\treturn this.metadata?.disposition === 'archived';\n\t}\n\n\t@memoize()\n\tget basename(): string {\n\t\tconst name = this.nameWithoutRemote;\n\t\tconst index = name.lastIndexOf('/');\n\t\treturn index !== -1 ? name.substring(index + 1) : name;\n\t}\n\n\tget disposition(): BranchDisposition | undefined {\n\t\treturn this.metadata?.disposition;\n\t}\n\n\t/** @returns The most recent date among lastModifiedDate, lastAccessedDate, and branch.date */\n\tget effectiveDate(): Date | undefined {\n\t\tlet maxTime: number | undefined;\n\n\t\tconst accessed = this.lastAccessedDate?.getTime();\n\t\tif (accessed != null && (maxTime == null || accessed > maxTime)) {\n\t\t\tmaxTime = accessed;\n\t\t}\n\n\t\tconst modified = this.lastModifiedDate?.getTime();\n\t\tif (modified != null && (maxTime == null || modified > maxTime)) {\n\t\t\tmaxTime = modified;\n\t\t}\n\n\t\tconst date = this.date?.getTime();\n\t\tif (date != null && (maxTime == null || date > maxTime)) {\n\t\t\tmaxTime = date;\n\t\t}\n\n\t\treturn maxTime != null ? new Date(maxTime) : undefined;\n\t}\n\n\tget lastAccessedDate(): Date | undefined {\n\t\treturn this.metadata != null ? getStampDate(this.metadata, 'lastAccessedAt') : undefined;\n\t}\n\n\t/** When a checkout's working tree or index last changed while on this branch (`gk-last-modified`), not only commits */\n\tget lastModifiedDate(): Date | undefined {\n\t\treturn this.metadata != null ? getStampDate(this.metadata, 'lastModifiedAt') : undefined;\n\t}\n\n\t@memoize()\n\tget nameWithoutRemote(): string {\n\t\treturn this.remote ? this.name.substring(getRemoteNameSlashIndex(this.name) + 1) : this.name;\n\t}\n\n\tget ref(): string {\n\t\treturn this.detached ? this.sha! : this._name;\n\t}\n\n\t@memoize()\n\tget remoteName(): string | undefined {\n\t\tif (this.remote) return getRemoteNameFromBranchName(this.name);\n\t\tif (this.upstream != null) return this.upstream.remote ?? getRemoteNameFromBranchName(this.upstream.name);\n\n\t\treturn undefined;\n\t}\n\n\tget starred(): boolean {\n\t\treturn this.metadata?.disposition === 'starred';\n\t}\n\n\tget status(): GitBranchStatus {\n\t\tif (this.remote) return 'remote';\n\t\tif (this.upstream == null) return this.detached ? 'detached' : 'local';\n\n\t\tif (this.upstream.missing) return 'missingUpstream';\n\t\tif (this.upstream.state.ahead && this.upstream.state.behind) return 'diverged';\n\t\tif (this.upstream.state.ahead) return 'ahead';\n\t\tif (this.upstream.state.behind) return 'behind';\n\t\treturn 'upToDate';\n\t}\n\n\t@memoize()\n\tget trackingWithoutRemote(): string | undefined {\n\t\treturn getBranchTrackingWithoutRemote(this);\n\t}\n\n\t/** Creates a copy of this branch with a different repoPath and optionally a different current flag — ONLY used for worktree-aware caching */\n\twithRepoPath(repoPath: string, current?: boolean): GitBranch {\n\t\tconst newCurrent = current ?? this.current;\n\t\tif (repoPath === this.repoPath && newCurrent === this.current) return this;\n\t\treturn new GitBranch(\n\t\t\trepoPath,\n\t\t\tthis.refName,\n\t\t\tnewCurrent,\n\t\t\tthis.date,\n\t\t\tthis.metadata,\n\t\t\tthis.sha,\n\t\t\tthis.upstream,\n\t\t\tthis.worktree,\n\t\t\tthis.detached,\n\t\t\tthis.rebasing,\n\t\t);\n\t}\n\n\tstatic is(branch: unknown): branch is GitBranch {\n\t\treturn branch instanceof GitBranch;\n\t}\n\n\tstatic formatDate(branch: GitBranchShape, format?: string | null): string {\n\t\treturn branch.date != null ? formatDate(branch.date, format ?? 'MMMM Do, YYYY h:mma') : '';\n\t}\n\n\tstatic formatDateFromNow(branch: GitBranchShape): string {\n\t\treturn branch.date != null ? fromNow(branch.date) : '';\n\t}\n\n\tstatic formatDateWithStyle(\n\t\tbranch: GitBranchShape,\n\t\tformatting: { dateStyle: string; dateFormat: string | null },\n\t): string {\n\t\treturn formatting.dateStyle === 'absolute'\n\t\t\t? GitBranch.formatDate(branch, formatting.dateFormat)\n\t\t\t: GitBranch.formatDateFromNow(branch);\n\t}\n\n\tstatic getTrackingStatus(\n\t\tbranch: GitBranchShape,\n\t\toptions?: {\n\t\t\tcount?: boolean;\n\t\t\tempty?: string;\n\t\t\texpand?: boolean;\n\t\t\ticons?: boolean;\n\t\t\tprefix?: string;\n\t\t\tseparator?: string;\n\t\t\tsuffix?: string;\n\t\t},\n\t): string {\n\t\treturn getUpstreamStatus(branch.upstream, options);\n\t}\n}\n\nexport interface GitTrackingState {\n\treadonly ahead: number;\n\treadonly behind: number;\n}\n\nexport interface GitTrackingUpstream {\n\treadonly name: string;\n\t/**\n\t * The remote the upstream is on (`branch.<name>.remote`) as git reports it, so a remote whose own name contains a\n\t * `/` stays whole. `undefined` when git is too old to report it (before 2.23 here) or the upstream is a local branch\n\t */\n\treadonly remote?: string;\n\treadonly missing: boolean;\n\treadonly state: GitTrackingState;\n}\n\nexport type GitBranchStatus =\n\t| 'local'\n\t| 'detached'\n\t| 'ahead'\n\t| 'behind'\n\t| 'diverged'\n\t| 'upToDate'\n\t| 'missingUpstream'\n\t| 'remote';\n\nexport interface BranchTargetInfo {\n\tmergeTargetBranch: MaybePausedResult<string | undefined>;\n\tbaseBranch: string | undefined;\n\tdefaultBranch: string | undefined;\n}\n"],"mappings":"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"}
@@ -9,6 +9,7 @@ export interface GitBranchReference {
9
9
  readonly upstream?: {
10
10
  name: string;
11
11
  missing: boolean;
12
+ remote?: string;
12
13
  };
13
14
  readonly worktree?: {
14
15
  path: string;
@@ -76,6 +77,8 @@ export interface RefRecord {
76
77
  authorDate: string;
77
78
  subject: string;
78
79
  worktreePath?: string;
80
+ /** `%(upstream:remotename)` — the remote a local branch tracks on (`.` for a local upstream); only read where git supports it */
81
+ upstreamRemote?: string;
79
82
  }
80
83
  //#endregion
81
84
  //# sourceMappingURL=reference.d.ts.map
@@ -1,10 +1,10 @@
1
1
  import { loggable } from "../../utils/decorators/log.js";
2
2
  import { memoize } from "../../utils/decorators/memoize.js";
3
+ import { formatDetachedHeadName, isDetachedHead } from "../utils/branch.utils.js";
3
4
  import __decorate from "../../_virtual/@oxc-project+runtime/helpers/esm/decorate.js";
4
5
  import { serializable } from "../../utils/decorators/serializable.js";
5
- import { GitFileConflictStatus, GitFileIndexStatus, GitFileWorkingTreeStatus } from "./fileStatus.js";
6
- import { formatDetachedHeadName, isDetachedHead } from "../utils/branch.utils.js";
7
6
  import { getFormattedDiffStatus, getUpstreamStatus } from "../utils/status.utils.js";
7
+ import { GitFileConflictStatus, GitFileIndexStatus, GitFileWorkingTreeStatus } from "./fileStatus.js";
8
8
  //#region ../git/src/models/status.ts
9
9
  var _GitStatus;
10
10
  let GitStatus = _GitStatus = class GitStatus {
@@ -24,7 +24,10 @@ export declare class GitWorktree {
24
24
  readonly name: string;
25
25
  } | undefined);
26
26
  get date(): Date | undefined;
27
- /** @returns The most recent date among lastModifiedDate, lastAccessedDate, and branch.date */
27
+ /**
28
+ * @returns The most recent date among lastModifiedDate, lastAccessedDate, and branch.date. Not memoized: the stamps
29
+ * change in place (see `BranchMetadata`)
30
+ */
28
31
  get effectiveDate(): Date | undefined;
29
32
  /** Timestamp when the worktree branch was last accessed or modified */
30
33
  get lastAccessedDate(): Date | undefined;
@@ -33,7 +33,10 @@ let GitWorktree = _GitWorktree = class GitWorktree {
33
33
  get date() {
34
34
  return this.branch?.date;
35
35
  }
36
- /** @returns The most recent date among lastModifiedDate, lastAccessedDate, and branch.date */
36
+ /**
37
+ * @returns The most recent date among lastModifiedDate, lastAccessedDate, and branch.date. Not memoized: the stamps
38
+ * change in place (see `BranchMetadata`)
39
+ */
37
40
  get effectiveDate() {
38
41
  let maxTime;
39
42
  const accessed = this.lastAccessedDate?.getTime();
@@ -95,7 +98,6 @@ let GitWorktree = _GitWorktree = class GitWorktree {
95
98
  return getRepositoryService(worktree.path)?.status.hasWorkingChanges(options);
96
99
  }
97
100
  };
98
- __decorate([memoize()], GitWorktree.prototype, "effectiveDate", null);
99
101
  __decorate([memoize()], GitWorktree.prototype, "friendlyPath", null);
100
102
  __decorate([memoize()], GitWorktree.prototype, "name", null);
101
103
  GitWorktree = _GitWorktree = __decorate([loggable((i) => i.uri.toString()), serializable], GitWorktree);
@@ -1 +1 @@
1
- {"version":3,"file":"worktree.js","names":[],"sources":["../../../../git/src/models/worktree.ts"],"sourcesContent":["import { formatDate, fromNow } from '@gitlens/utils/date.js';\nimport { loggable } from '@gitlens/utils/decorators/log.js';\nimport { memoize } from '@gitlens/utils/decorators/memoize.js';\nimport { serializable } from '@gitlens/utils/decorators/serializable.js';\nimport { basename, normalizePath, relative } from '@gitlens/utils/path.js';\nimport type { Shape } from '@gitlens/utils/types.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { getRepositoryService } from '../repositoryService.js';\nimport type { GitCommandPriority } from '../run.types.js';\nimport { getRepositoryOrWorktreePath } from '../utils/repository.utils.js';\nimport { shortenRevision } from '../utils/revision.utils.js';\nimport type { GitBranch } from './branch.js';\nimport type { GitStatus } from './status.js';\n\nexport type GitWorktreeShape = Shape<GitWorktree>;\n\nexport type WorkspaceFolderResolver = (uri: Uri) => GitWorktree['workspaceFolder'] | undefined;\n\n@loggable(i => i.uri.toString())\n@serializable\nexport class GitWorktree {\n\tconstructor(\n\t\tpublic readonly isDefault: boolean,\n\t\tpublic readonly type: 'bare' | 'branch' | 'detached',\n\t\tpublic readonly repoPath: string,\n\t\tpublic readonly uri: Uri,\n\t\tpublic readonly locked: boolean | string,\n\t\tpublic readonly prunable: boolean | string,\n\t\tpublic readonly sha?: string,\n\t\tpublic readonly branch?: GitBranch,\n\t\tpublic readonly workspaceFolder?: { readonly uri: Uri; readonly name: string },\n\t) {}\n\n\tget date(): Date | undefined {\n\t\treturn this.branch?.date;\n\t}\n\n\t/** @returns The most recent date among lastModifiedDate, lastAccessedDate, and branch.date */\n\t@memoize()\n\tget effectiveDate(): Date | undefined {\n\t\tlet maxTime: number | undefined;\n\n\t\tconst accessed = this.lastAccessedDate?.getTime();\n\t\tif (accessed != null && (maxTime == null || accessed > maxTime)) {\n\t\t\tmaxTime = accessed;\n\t\t}\n\n\t\tconst modified = this.lastModifiedDate?.getTime();\n\t\tif (modified != null && (maxTime == null || modified > maxTime)) {\n\t\t\tmaxTime = modified;\n\t\t}\n\n\t\tconst date = this.branch?.date?.getTime();\n\t\tif (date != null && (maxTime == null || date > maxTime)) {\n\t\t\tmaxTime = date;\n\t\t}\n\n\t\treturn maxTime != null ? new Date(maxTime) : undefined;\n\t}\n\n\t/** Timestamp when the worktree branch was last accessed or modified */\n\tget lastAccessedDate(): Date | undefined {\n\t\treturn this.branch?.lastAccessedDate;\n\t}\n\n\t/** Timestamp when the worktree branch was last modified (working changes / index) */\n\tget lastModifiedDate(): Date | undefined {\n\t\treturn this.branch?.lastModifiedDate;\n\t}\n\n\t@memoize()\n\tget friendlyPath(): string {\n\t\tif (this.workspaceFolder != null) {\n\t\t\tconst relativePath = normalizePath(relative(this.workspaceFolder.uri.fsPath, this.uri.fsPath));\n\t\t\treturn relativePath || this.workspaceFolder.name;\n\t\t}\n\n\t\tconst relativePath = normalizePath(relative(this.repoPath, this.uri.fsPath));\n\t\treturn relativePath || normalizePath(this.uri.fsPath);\n\t}\n\n\t@memoize()\n\tget name(): string {\n\t\tswitch (this.type) {\n\t\t\tcase 'bare':\n\t\t\t\treturn '(bare)';\n\t\t\tcase 'detached':\n\t\t\t\treturn `${basename(this.path)} (${shortenRevision(this.sha)})`;\n\t\t\tdefault:\n\t\t\t\treturn this.branch?.name || this.friendlyPath;\n\t\t}\n\t}\n\n\tget opened(): boolean {\n\t\treturn this.workspaceFolder?.uri.toString() === this.uri.toString();\n\t}\n\n\tget path(): string {\n\t\treturn getRepositoryOrWorktreePath(this.uri);\n\t}\n\n\t/** Creates a copy of this worktree with a different repoPath and updated branch — ONLY used for worktree-aware caching */\n\twithRepoPath(repoPath: string): GitWorktree {\n\t\tif (repoPath === this.repoPath) return this;\n\n\t\treturn new GitWorktree(\n\t\t\tthis.isDefault,\n\t\t\tthis.type,\n\t\t\trepoPath,\n\t\t\tthis.uri,\n\t\t\tthis.locked,\n\t\t\tthis.prunable,\n\t\t\tthis.sha,\n\t\t\tthis.branch?.withRepoPath(repoPath, true),\n\t\t\tthis.workspaceFolder,\n\t\t);\n\t}\n\n\tstatic is(worktree: unknown): worktree is GitWorktree {\n\t\treturn worktree instanceof GitWorktree;\n\t}\n\n\tstatic formatDate(worktree: GitWorktreeShape, format?: string | null): string {\n\t\treturn worktree.date != null ? formatDate(worktree.date, format ?? 'MMMM Do, YYYY h:mma') : '';\n\t}\n\n\tstatic formatDateFromNow(worktree: GitWorktreeShape): string {\n\t\treturn worktree.date != null ? fromNow(worktree.date) : '';\n\t}\n\n\tstatic formatDateWithStyle(\n\t\tworktree: GitWorktreeShape,\n\t\tformatting: { dateStyle: string; dateFormat: string | null },\n\t): string {\n\t\treturn formatting.dateStyle === 'absolute'\n\t\t\t? GitWorktree.formatDate(worktree, formatting.dateFormat)\n\t\t\t: GitWorktree.formatDateFromNow(worktree);\n\t}\n\n\tstatic async getStatus(\n\t\tworktree: GitWorktree,\n\t\toptions?: { priority?: GitCommandPriority },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatus | undefined> {\n\t\tif (worktree.type === 'bare') return undefined;\n\n\t\tconst repo = getRepositoryService(worktree.path);\n\t\treturn repo?.status.getStatus(options, cancellation);\n\t}\n\n\tstatic async hasWorkingChanges(\n\t\tworktree: GitWorktree,\n\t\toptions?: { staged?: boolean; unstaged?: boolean; untracked?: boolean },\n\t): Promise<boolean | undefined> {\n\t\tif (worktree.type === 'bare') return undefined;\n\n\t\tconst repo = getRepositoryService(worktree.path);\n\t\treturn repo?.status.hasWorkingChanges(options);\n\t}\n}\n"],"mappings":";;;;;;;;;;;AAoBO,IAAM,cAAA,eAAN,MAAM,YAAY;CAEP;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CATjB,YACC,WACA,MACA,UACA,KACA,QACA,UACA,KACA,QACA,iBACC;EATe,KAAA,YAAA;EACA,KAAA,OAAA;EACA,KAAA,WAAA;EACA,KAAA,MAAA;EACA,KAAA,SAAA;EACA,KAAA,WAAA;EACA,KAAA,MAAA;EACA,KAAA,SAAA;EACA,KAAA,kBAAA;CACd;CAEH,IAAI,OAAyB;EAC5B,OAAO,KAAK,QAAQ;CACrB;;CAGA,IACI,gBAAkC;EACrC,IAAI;EAEJ,MAAM,WAAW,KAAK,kBAAkB,QAAQ;EAChD,IAAI,YAAY,SAAS,WAAW,QAAQ,WAAW,UACtD,UAAU;EAGX,MAAM,WAAW,KAAK,kBAAkB,QAAQ;EAChD,IAAI,YAAY,SAAS,WAAW,QAAQ,WAAW,UACtD,UAAU;EAGX,MAAM,OAAO,KAAK,QAAQ,MAAM,QAAQ;EACxC,IAAI,QAAQ,SAAS,WAAW,QAAQ,OAAO,UAC9C,UAAU;EAGX,OAAO,WAAW,OAAO,IAAI,KAAK,OAAO,IAAI,KAAA;CAC9C;;CAGA,IAAI,mBAAqC;EACxC,OAAO,KAAK,QAAQ;CACrB;;CAGA,IAAI,mBAAqC;EACxC,OAAO,KAAK,QAAQ;CACrB;CAEA,IACI,eAAuB;EAC1B,IAAI,KAAK,mBAAmB,MAE3B,OADqB,cAAc,SAAS,KAAK,gBAAgB,IAAI,QAAQ,KAAK,IAAI,MAAM,CAC1E,KAAK,KAAK,gBAAgB;EAI7C,OADqB,cAAc,SAAS,KAAK,UAAU,KAAK,IAAI,MAAM,CACxD,KAAK,cAAc,KAAK,IAAI,MAAM;CACrD;CAEA,IACI,OAAe;EAClB,QAAQ,KAAK,MAAb;GACC,KAAK,QACJ,OAAO;GACR,KAAK,YACJ,OAAO,GAAG,SAAS,KAAK,IAAI,EAAE,IAAI,gBAAgB,KAAK,GAAG,EAAE;GAC7D,SACC,OAAO,KAAK,QAAQ,QAAQ,KAAK;EACnC;CACD;CAEA,IAAI,SAAkB;EACrB,OAAO,KAAK,iBAAiB,IAAI,SAAS,MAAM,KAAK,IAAI,SAAS;CACnE;CAEA,IAAI,OAAe;EAClB,OAAO,4BAA4B,KAAK,GAAG;CAC5C;;CAGA,aAAa,UAA+B;EAC3C,IAAI,aAAa,KAAK,UAAU,OAAO;EAEvC,OAAO,IAAA,aACN,KAAK,WACL,KAAK,MACL,UACA,KAAK,KACL,KAAK,QACL,KAAK,UACL,KAAK,KACL,KAAK,QAAQ,aAAa,UAAU,IAAI,GACxC,KAAK,eACN;CACD;CAEA,OAAO,GAAG,UAA4C;EACrD,OAAO,oBAAA;CACR;CAEA,OAAO,WAAW,UAA4B,QAAgC;EAC7E,OAAO,SAAS,QAAQ,OAAO,WAAW,SAAS,MAAM,UAAU,qBAAqB,IAAI;CAC7F;CAEA,OAAO,kBAAkB,UAAoC;EAC5D,OAAO,SAAS,QAAQ,OAAO,QAAQ,SAAS,IAAI,IAAI;CACzD;CAEA,OAAO,oBACN,UACA,YACS;EACT,OAAO,WAAW,cAAc,aAAA,aACjB,WAAW,UAAU,WAAW,UAAU,IAAA,aAC1C,kBAAkB,QAAQ;CAC1C;CAEA,aAAa,UACZ,UACA,SACA,cACiC;EACjC,IAAI,SAAS,SAAS,QAAQ,OAAO,KAAA;EAGrC,OADa,qBAAqB,SAAS,IACjC,CAAC,EAAE,OAAO,UAAU,SAAS,YAAY;CACpD;CAEA,aAAa,kBACZ,UACA,SAC+B;EAC/B,IAAI,SAAS,SAAS,QAAQ,OAAO,KAAA;EAGrC,OADa,qBAAqB,SAAS,IACjC,CAAC,EAAE,OAAO,kBAAkB,OAAO;CAC9C;AACD;AAzHE,WAAA,CAAA,QAAQ,CAAA,GAAA,YAAA,WAAA,iBAAA,IAAA;AAgCR,WAAA,CAAA,QAAQ,CAAA,GAAA,YAAA,WAAA,gBAAA,IAAA;AAWR,WAAA,CAAA,QAAQ,CAAA,GAAA,YAAA,WAAA,QAAA,IAAA;AA/DT,cAAA,eAAA,WAAA,CAAA,UAAS,MAAK,EAAE,IAAI,SAAS,CAAC,GAC9B,YAAA,GAAA,WAAA"}
1
+ {"version":3,"file":"worktree.js","names":[],"sources":["../../../../git/src/models/worktree.ts"],"sourcesContent":["import { formatDate, fromNow } from '@gitlens/utils/date.js';\nimport { loggable } from '@gitlens/utils/decorators/log.js';\nimport { memoize } from '@gitlens/utils/decorators/memoize.js';\nimport { serializable } from '@gitlens/utils/decorators/serializable.js';\nimport { basename, normalizePath, relative } from '@gitlens/utils/path.js';\nimport type { Shape } from '@gitlens/utils/types.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { getRepositoryService } from '../repositoryService.js';\nimport type { GitCommandPriority } from '../run.types.js';\nimport { getRepositoryOrWorktreePath } from '../utils/repository.utils.js';\nimport { shortenRevision } from '../utils/revision.utils.js';\nimport type { GitBranch } from './branch.js';\nimport type { GitStatus } from './status.js';\n\nexport type GitWorktreeShape = Shape<GitWorktree>;\n\nexport type WorkspaceFolderResolver = (uri: Uri) => GitWorktree['workspaceFolder'] | undefined;\n\n@loggable(i => i.uri.toString())\n@serializable\nexport class GitWorktree {\n\tconstructor(\n\t\tpublic readonly isDefault: boolean,\n\t\tpublic readonly type: 'bare' | 'branch' | 'detached',\n\t\tpublic readonly repoPath: string,\n\t\tpublic readonly uri: Uri,\n\t\tpublic readonly locked: boolean | string,\n\t\tpublic readonly prunable: boolean | string,\n\t\tpublic readonly sha?: string,\n\t\tpublic readonly branch?: GitBranch,\n\t\tpublic readonly workspaceFolder?: { readonly uri: Uri; readonly name: string },\n\t) {}\n\n\tget date(): Date | undefined {\n\t\treturn this.branch?.date;\n\t}\n\n\t/**\n\t * @returns The most recent date among lastModifiedDate, lastAccessedDate, and branch.date. Not memoized: the stamps\n\t * change in place (see `BranchMetadata`)\n\t */\n\tget effectiveDate(): Date | undefined {\n\t\tlet maxTime: number | undefined;\n\n\t\tconst accessed = this.lastAccessedDate?.getTime();\n\t\tif (accessed != null && (maxTime == null || accessed > maxTime)) {\n\t\t\tmaxTime = accessed;\n\t\t}\n\n\t\tconst modified = this.lastModifiedDate?.getTime();\n\t\tif (modified != null && (maxTime == null || modified > maxTime)) {\n\t\t\tmaxTime = modified;\n\t\t}\n\n\t\tconst date = this.branch?.date?.getTime();\n\t\tif (date != null && (maxTime == null || date > maxTime)) {\n\t\t\tmaxTime = date;\n\t\t}\n\n\t\treturn maxTime != null ? new Date(maxTime) : undefined;\n\t}\n\n\t/** Timestamp when the worktree branch was last accessed or modified */\n\tget lastAccessedDate(): Date | undefined {\n\t\treturn this.branch?.lastAccessedDate;\n\t}\n\n\t/** Timestamp when the worktree branch was last modified (working changes / index) */\n\tget lastModifiedDate(): Date | undefined {\n\t\treturn this.branch?.lastModifiedDate;\n\t}\n\n\t@memoize()\n\tget friendlyPath(): string {\n\t\tif (this.workspaceFolder != null) {\n\t\t\tconst relativePath = normalizePath(relative(this.workspaceFolder.uri.fsPath, this.uri.fsPath));\n\t\t\treturn relativePath || this.workspaceFolder.name;\n\t\t}\n\n\t\tconst relativePath = normalizePath(relative(this.repoPath, this.uri.fsPath));\n\t\treturn relativePath || normalizePath(this.uri.fsPath);\n\t}\n\n\t@memoize()\n\tget name(): string {\n\t\tswitch (this.type) {\n\t\t\tcase 'bare':\n\t\t\t\treturn '(bare)';\n\t\t\tcase 'detached':\n\t\t\t\treturn `${basename(this.path)} (${shortenRevision(this.sha)})`;\n\t\t\tdefault:\n\t\t\t\treturn this.branch?.name || this.friendlyPath;\n\t\t}\n\t}\n\n\tget opened(): boolean {\n\t\treturn this.workspaceFolder?.uri.toString() === this.uri.toString();\n\t}\n\n\tget path(): string {\n\t\treturn getRepositoryOrWorktreePath(this.uri);\n\t}\n\n\t/** Creates a copy of this worktree with a different repoPath and updated branch — ONLY used for worktree-aware caching */\n\twithRepoPath(repoPath: string): GitWorktree {\n\t\tif (repoPath === this.repoPath) return this;\n\n\t\treturn new GitWorktree(\n\t\t\tthis.isDefault,\n\t\t\tthis.type,\n\t\t\trepoPath,\n\t\t\tthis.uri,\n\t\t\tthis.locked,\n\t\t\tthis.prunable,\n\t\t\tthis.sha,\n\t\t\tthis.branch?.withRepoPath(repoPath, true),\n\t\t\tthis.workspaceFolder,\n\t\t);\n\t}\n\n\tstatic is(worktree: unknown): worktree is GitWorktree {\n\t\treturn worktree instanceof GitWorktree;\n\t}\n\n\tstatic formatDate(worktree: GitWorktreeShape, format?: string | null): string {\n\t\treturn worktree.date != null ? formatDate(worktree.date, format ?? 'MMMM Do, YYYY h:mma') : '';\n\t}\n\n\tstatic formatDateFromNow(worktree: GitWorktreeShape): string {\n\t\treturn worktree.date != null ? fromNow(worktree.date) : '';\n\t}\n\n\tstatic formatDateWithStyle(\n\t\tworktree: GitWorktreeShape,\n\t\tformatting: { dateStyle: string; dateFormat: string | null },\n\t): string {\n\t\treturn formatting.dateStyle === 'absolute'\n\t\t\t? GitWorktree.formatDate(worktree, formatting.dateFormat)\n\t\t\t: GitWorktree.formatDateFromNow(worktree);\n\t}\n\n\tstatic async getStatus(\n\t\tworktree: GitWorktree,\n\t\toptions?: { priority?: GitCommandPriority },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatus | undefined> {\n\t\tif (worktree.type === 'bare') return undefined;\n\n\t\tconst repo = getRepositoryService(worktree.path);\n\t\treturn repo?.status.getStatus(options, cancellation);\n\t}\n\n\tstatic async hasWorkingChanges(\n\t\tworktree: GitWorktree,\n\t\toptions?: { staged?: boolean; unstaged?: boolean; untracked?: boolean },\n\t): Promise<boolean | undefined> {\n\t\tif (worktree.type === 'bare') return undefined;\n\n\t\tconst repo = getRepositoryService(worktree.path);\n\t\treturn repo?.status.hasWorkingChanges(options);\n\t}\n}\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { fileUri, joinUriPath } from "../../utils/uri.js";
2
2
  import { normalizePath } from "../../utils/path.js";
3
3
  import { GitFileIndexStatus } from "../models/fileStatus.js";
4
- import { GitFileChange } from "../models/fileChange.js";
5
4
  import { maybeStopWatch } from "../../utils/stopwatch.js";
6
5
  import _usingCtx from "../../_virtual/@oxc-project+runtime/helpers/esm/usingCtx.js";
6
+ import { GitFileChange } from "../models/fileChange.js";
7
7
  //#region ../git/src/parsers/diffParser.ts
8
8
  const diffRegex = /^diff --git a\/(.*) b\/(.*)$/;
9
9
  const diffHunkRegex = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
@@ -21,6 +21,8 @@ export interface BranchContributionsOverview extends GitCommitStats<number> {
21
21
  readonly firstCommitDate: Date | undefined;
22
22
  readonly contributors: GitContributor[];
23
23
  }
24
+ /** Which source decided a base (see `getAheadOfBase`) */
25
+ export type AheadOfBaseTier = 'preferred' | 'user' | 'detected' | 'recorded' | 'created' | 'default' | 'upstream';
24
26
  export interface AheadOfBase {
25
27
  /** The base HEAD was measured against; `undefined` when there is none (see `getAheadOfBase`) */
26
28
  readonly base: {
@@ -30,8 +32,14 @@ export interface AheadOfBase {
30
32
  readonly ahead: number;
31
33
  /** The commit `ref` pointed at, from the cached ref list; `undefined` when no listed ref matches it */
32
34
  readonly sha: string | undefined;
35
+ /** Where HEAD forked from `ref`: git's `--fork-point` reading of `ref`'s reflog, else the merge base; `undefined` when they share no history */
36
+ readonly forkPoint: string | undefined;
37
+ /** The source the base came from: the `preferredTarget` option, the user's merge target, the detected one, the base recorded against the branch, the branch git's reflog says this branch was created from (unless the default branch forked strictly nearer HEAD), the default branch, or — when the branch is the default branch — the branch's own upstream */
38
+ readonly tier: AheadOfBaseTier;
33
39
  } | undefined;
34
- /** Full ref names (`refs/heads/main`, `refs/remotes/origin/main`, `refs/remotes/origin/HEAD`) whose movement can change this answer, given with or without a base so a watcher also learns when one appears: the branch, every candidate compared up to the chosen one, their tracking refs, and the default-branch symref when the default was consulted. Lets a watcher recompute only when one of them moves. */
40
+ /** Why there is no base; set exactly when `base` is `undefined`: `'none'` when nothing resolved, `'self'` when the base is the branch itself at HEAD's commit (or the default branch has no upstream to measure against), `'unborn'` when HEAD has no commit yet */
41
+ readonly reason?: 'none' | 'self' | 'unborn';
42
+ /** Full ref names (`refs/heads/main`, `refs/remotes/origin/main`, `refs/remotes/origin/HEAD`) whose movement can change this answer, given with or without a base so a watcher also learns when one appears: the branch, every candidate compared up to the chosen one, their tracking refs, the default-branch symrefs and the `<remote>/main`/`<remote>/master` refs when the default was consulted, the `upstream` remote's copy of the created-from or default branch when it was compared, and the branch's upstream when it is the default branch. Lets a watcher recompute only when one of them moves. */
35
43
  readonly dependsOn: readonly string[];
36
44
  }
37
45
  export type MergeDetectionConfidence = 'highest' | 'high' | 'medium';
@@ -99,16 +107,61 @@ export interface GitBranchesSubProvider {
99
107
  /** Detects conflicts when an autostash is reapplied onto the tree an integration produced */
100
108
  getPotentialStashReapplyConflicts?(repoPath: string, ontoTreeOid: string, cancellation?: AbortSignal): Promise<ConflictDetectionResult>;
101
109
  /**
102
- * How far HEAD has moved past the base `branch` (the branch checked out at HEAD) was cut from. Candidates in trust
110
+ * How far HEAD has moved past the base `branch` (the branch checked out at HEAD, or `undefined` when HEAD is
111
+ * detached) was cut from. Candidates in trust
103
112
  * order: the user's merge target, the detected one, then the base recorded against the branch — only recorded bases
104
113
  * count, never a reflog guess. Each is measured as itself or its tracking ref, whichever forked nearer HEAD; a stale
105
- * target (one naming no ref, a flag-like one, or the branch itself) falls through to the next, and the local default
106
- * branch is used when none survives. The count is the right side of `<base>...HEAD`. `base` is `undefined` when no
107
- * base resolves, when the base is the branch itself (by name, or as its copy on one of the repo's remotes) at HEAD's
108
- * own commit, or when HEAD is detached or has no commit yet; `dependsOn` is given either way. `base.sha` is the tip of
109
- * `ref`, read from the cached ref list. Rejects when the count can't be read.
114
+ * target (one naming no ref, a flag-like one, or the branch itself) falls through to the next, and the default branch
115
+ * is used when none survives: the `HEAD` symref of the `upstream` remote, else `origin`, else the first remote, as its
116
+ * local branch or else the remote ref; then, in the same remote order, `<remote>/main` or `<remote>/master`, again as
117
+ * the local branch or else the remote ref; then `init.defaultBranch`, `main`, `master` — from local refs only, never
118
+ * the network. On the default branch itself the base is its upstream (`upstream/<branch>` when an `upstream` remote has
119
+ * it, else `<branch>@{u}`), tier `'upstream'`. The count is the right side of `<base>...HEAD`. `base` is `undefined`
120
+ * when no base resolves, when the base is the branch itself (by name, or as its copy on one of the repo's remotes) at
121
+ * HEAD's own commit — or the default branch has no upstream — or when HEAD has no commit yet; `reason`
122
+ * then says which (`'none'`, `'self'` or `'unborn'`) and `dependsOn` is given either way. `base.sha` is the tip of
123
+ * `ref`, read from the cached ref list; `base.forkPoint` is where HEAD forked from `ref` and `base.tier` the source
124
+ * that decided the base. On a detached HEAD (`undefined`, or a name `isDetachedHead` recognizes) only the default branch
125
+ * is tried, as tier `'default'` and with no self check. Rejects when the count can't be read.
126
+ *
127
+ * `options.skipUserTarget` leaves the user's merge target out, giving the order a merge-target picker shows as
128
+ * "automatic". `options.preferredTarget` is tried before every other source, also on a detached HEAD, and measured
129
+ * like a recorded candidate (tier `'preferred'`); one that is unusable — naming no ref, flag-like, the branch itself,
130
+ * or the branch's copy on one of the repo's remotes at HEAD's own commit — falls through to the usual order.
131
+ * Tier `'preferred'` means the preferred target is the base; any other tier, or no base, means it fell through.
110
132
  */
111
- getAheadOfBase?(repoPath: string, branch: string, cancellation?: AbortSignal): Promise<AheadOfBase>;
133
+ getAheadOfBase?(repoPath: string, branch: string | undefined, options?: {
134
+ /** Leaves the user's merge target out: the order a merge-target picker shows as "automatic" */
135
+ skipUserTarget?: boolean;
136
+ /** A target to try before every other source */
137
+ preferredTarget?: string;
138
+ }, cancellation?: AbortSignal): Promise<AheadOfBase>;
139
+ /**
140
+ * How far each branch has diverged from `base`, keyed by full ref name (`refs/heads/x`, plus `refs/remotes/<remote>/x`
141
+ * when `options.remotes` is set) so a local and a remote name can't collide. Symbolic refs such as
142
+ * `refs/remotes/origin/HEAD` are left out. `ahead` is the commits on the branch that `base` lacks and `behind` the
143
+ * commits on `base` that the branch lacks, i.e. the right and left sides of `base...branch`. `options.refs` limits it to
144
+ * those full ref names (in place of `remotes`), so a host counts only the branches it shows; an empty list answers
145
+ * empty without running git. One git run on git 2.41+, a bounded count per distinct tip before that. Rejects when
146
+ * `base` can't be resolved or the counts can't be read.
147
+ */
148
+ getAheadBehindCounts?(repoPath: string, base: string, options?: {
149
+ remotes?: boolean;
150
+ refs?: readonly string[];
151
+ }, cancellation?: AbortSignal): Promise<Map<string, {
152
+ ahead: number;
153
+ behind: number;
154
+ }>>;
155
+ /**
156
+ * The branches whose tips are reachable from `into`, as full ref names (`refs/heads/x`, plus `refs/remotes/<remote>/x`
157
+ * when `options.remotes` is set). Ancestry only: a branch squash-merged or cherry-picked into `into` is not included,
158
+ * so use `getBranchMergedStatus` for that heuristic per-branch answer. A branch whose tip equals `into`'s tip (never
159
+ * diverged) is included, as git reports it. Symbolic refs such as `refs/remotes/origin/HEAD` are left out. One git
160
+ * run. Not cached. Rejects when `into` can't be resolved or the branches can't be read.
161
+ */
162
+ getMergedBranches?(repoPath: string, into: string, options?: {
163
+ remotes?: boolean;
164
+ }, cancellation?: AbortSignal): Promise<Set<string>>;
112
165
  getBaseBranchName?(repoPath: string, ref: string, options?: {
113
166
  priority?: GitCommandPriority;
114
167
  }, cancellation?: AbortSignal): Promise<string | undefined>;
@@ -118,8 +171,20 @@ export interface GitBranchesSubProvider {
118
171
  }, cancellation?: AbortSignal): Promise<string | undefined>;
119
172
  getStoredDetectedMergeTargetBranchName?(repoPath: string, ref: string): Promise<string | undefined>;
120
173
  getStoredUserMergeTargetBranchName?(repoPath: string, ref: string): Promise<string | undefined>;
174
+ /**
175
+ * Stamps `branch.<name>.gk-last-accessed` in `.git/gk/config` for the branch checked out at `repoPath`, when the
176
+ * host checks it out or opens it. A no-op for a detached HEAD or no branch. Each key's write is attempted at most
177
+ * once per 5 minutes per branch, failed or not, and not when its stored value, from any process, is under 5 minutes
178
+ * old. Calls for different repositories never drop each other, and the promise settles once the write is done and
179
+ * never rejects.
180
+ */
121
181
  onCurrentBranchAccessed?(repoPath: string): Promise<void>;
182
+ /**
183
+ * Stamps `gk-last-modified` and `gk-last-accessed`: the checkout's working tree or index changed while on the
184
+ * branch — file edits and staging, not only commits. Otherwise as {@link onCurrentBranchAccessed}.
185
+ */
122
186
  onCurrentBranchModified?(repoPath: string): Promise<void>;
187
+ /** Stamps `gk-agent-last-activity`: an AI agent worked in the checkout. Otherwise as {@link onCurrentBranchAccessed} */
123
188
  onCurrentBranchAgentActivity?(repoPath: string): Promise<void>;
124
189
  renameBranch?(repoPath: string, oldName: string, newName: string): Promise<void>;
125
190
  setUpstreamBranch?(repoPath: string, name: string, upstream: string | undefined): Promise<void>;
@@ -9,7 +9,8 @@ export interface GitOperationResult {
9
9
  }
10
10
  /**
11
11
  * Spawn-layer overrides callers can pass to user-initiated git operations to inject per-call
12
- * environment variables, an `AbortSignal` for cancellation, or a custom `timeout`. Forwarded
12
+ * environment variables, an `AbortSignal` for cancellation, a custom `timeout`, or a `beforeIndexLockRetry`
13
+ * hook to re-verify state before an index write is retried. Forwarded
13
14
  * verbatim to the underlying `git.run(...)` invocation; cannot override op-owned fields like
14
15
  * `cwd`, `configs`, `errors`, or `stdin`.
15
16
  *
@@ -17,7 +18,7 @@ export interface GitOperationResult {
17
18
  * intentionally disable the timeout (set it to 0) because those operations can take a long
18
19
  * time; a caller-supplied `timeout` will replace that "no timeout" setting, so use with care.
19
20
  */
20
- export type GitOperationRunOptions = Pick<GitRunOptions, 'env' | 'cancellation' | 'timeout'>;
21
+ export type GitOperationRunOptions = Pick<GitRunOptions, 'env' | 'cancellation' | 'timeout' | 'beforeIndexLockRetry'>;
21
22
  export interface GitOperationsSubProvider {
22
23
  /**
23
24
  * Switches the repository to a branch or ref. Pure branch/ref switching — does not accept
@@ -4,6 +4,12 @@ export interface GitPausedOperationsSubProvider {
4
4
  getPausedOperationStatus(repoPath: string, options?: {
5
5
  force?: boolean;
6
6
  }, cancellation?: AbortSignal): Promise<GitPausedOperationStatus | undefined>;
7
+ /**
8
+ * Whether git's dir holds a sentinel of any in-progress operation (merge, cherry-pick, revert, rebase,
9
+ * `git am`, or a sequencer run with a todo) — presence only, so it is `true` even for states
10
+ * `getPausedOperationStatus` can't describe. Rejects when git's dir can't be read, rather than answering `false`
11
+ */
12
+ hasPausedOperation?(repoPath: string, cancellation?: AbortSignal): Promise<boolean>;
7
13
  abortPausedOperation(repoPath: string, options?: {
8
14
  quit?: boolean;
9
15
  }): Promise<void>;
@@ -4,6 +4,7 @@ import { GitProviderDescriptor } from "./types.js";
4
4
  import { GitIgnoreFilter } from "../watching/gitIgnoreFilter.js";
5
5
  import { RepositoryChange } from "../models/repository.js";
6
6
  import { GitMaintenanceSubProvider } from "./maintenance.js";
7
+ import { GitCommandPriority } from "../run.types.js";
7
8
  import { GitCommitsSubProvider } from "./commits.js";
8
9
  import { GitBranchesSubProvider } from "./branches.js";
9
10
  import { GitContributorsSubProvider } from "./contributors.js";
@@ -24,6 +25,11 @@ import { GitStatusSubProvider } from "./status.js";
24
25
  import { GitTagsSubProvider } from "./tags.js";
25
26
  import { GitWorktreesSubProvider } from "./worktrees.js";
26
27
  //#region ../git/src/providers/provider.d.ts
28
+ /** One path a provider announced its own write for, with the changes it announced there */
29
+ export interface AnnouncedRepositoryChanges {
30
+ readonly repoPath: string;
31
+ readonly changes: readonly RepositoryChange[];
32
+ }
27
33
  /**
28
34
  * Common interface for all git providers (CLI, GitHub, etc.).
29
35
  * Consumers can register multiple providers and route operations transparently.
@@ -48,13 +54,50 @@ export interface GitProvider {
48
54
  * ancestor, and literal paths containing glob metacharacters are dropped (a watcher can't express them safely).
49
55
  */
50
56
  getIgnoredDirectories?(repoPath: string, cancellation?: AbortSignal): Promise<string[]>;
57
+ /**
58
+ * The working tree's ignored entries as repo-relative `/`-separated paths, the way `git status --ignored` lists
59
+ * them: an ignored file is one entry, and a directory whose entire contents are ignored is one entry with a
60
+ * trailing `/` (its contents aren't listed). Empty directories and `.git/` aren't listed. Sorted, and not capped —
61
+ * the caller limits what it shows. Unlike `getIgnoredDirectories` this is a listing, not a watcher-pruning set, so
62
+ * nothing is dropped or re-confirmed against the rules. `options.paths` limits the listing to those repo-relative
63
+ * folders (or files), matched literally rather than as globs, so only they are walked — an empty array answers
64
+ * empty without running git, and omitting it lists the whole working tree. `options.priority` (e.g.
65
+ * `'interactive'`) is for a caller waiting on the answer.
66
+ */
67
+ getIgnoredEntries?(repoPath: string, options?: {
68
+ paths?: readonly string[];
69
+ priority?: GitCommandPriority;
70
+ }, cancellation?: AbortSignal): Promise<string[]>;
71
+ /**
72
+ * An exact check of which of `paths` (repo-relative) git's ignore rules match — the subset that is ignored, as
73
+ * given. A tracked file isn't reported as ignored, even when a rule matches it. This is git's answer, where the
74
+ * in-memory `GitIgnoreFilter` errs toward not-ignored. Each path is checked as that exact file, never as pathspec
75
+ * magic (a file named `:secret` is not `secret`), and comes back in the caller's spelling. Pass
76
+ * `options.priority` (e.g. `'interactive'` when opening a file) for a caller waiting on the answer.
77
+ */
78
+ getIgnoredPaths?(repoPath: string, paths: readonly string[], options?: {
79
+ priority?: GitCommandPriority;
80
+ }, cancellation?: AbortSignal): Promise<Set<string>>;
51
81
  getIgnoredUrisFilter?(repoPath: string): Promise<(uri: Uri) => boolean>;
52
82
  getLastFetchedTimestamp?(repoPath: string): Promise<number | undefined>;
53
83
  /**
54
- * Fires when an external write changed a branch's merge-relevant `.git/gk/config` keys — not for activity
55
- * timestamps, and not for the provider's own writes. See `Cache.onDidChangeMergeTargets`.
84
+ * Fires when a write changed a branch's merge-relevant `.git/gk/config` keys — not for activity timestamps. The
85
+ * provider's own key store fires it once, naming the branch, as the write completes; its section remove and
86
+ * rename don't, nor do its internal saves while answering a read (only another process's watcher reports those).
87
+ * See `Cache.onDidChangeMergeTargets`.
56
88
  */
57
89
  readonly onDidChangeMergeTargets?: Event<MergeTargetsChangeEvent>;
90
+ /**
91
+ * The repository's common path, as it appears in {@link onDidChangeMergeTargets} events; `undefined` when the
92
+ * provider can't tell, because `repoPath` was never registered with it
93
+ */
94
+ getCommonPath?(repoPath: string): string | undefined;
95
+ /**
96
+ * Fires as the provider announces one of its own writes to the host (`hooks.repository.onChanged`), once for each
97
+ * path it announces it for, sibling worktrees included — after the write finished and its caches were evicted.
98
+ * `GitService` forwards it to its watch service, so the write's own file events aren't announced a second time.
99
+ */
100
+ readonly onDidAnnounceChanges?: Event<AnnouncedRepositoryChanges>;
58
101
  /** Creates a new repository at `path` (`git init`), creating `path` itself if it doesn't yet exist. */
59
102
  init?(path: string, options?: {
60
103
  defaultBranch?: string;
@@ -22,10 +22,24 @@ export interface GitRevisionSubProvider {
22
22
  getEmptyTreeSha(repoPath: string): Promise<string>;
23
23
  getRevisionContent(repoPath: string, path: string, rev: string): Promise<Uint8Array | undefined>;
24
24
  getSubmoduleHead?(repoPath: string, submodulePath: string): Promise<string | undefined>;
25
- /** Gets tracked file paths from the index (reflects working tree state, even during rebase) */
26
- getTrackedFiles(repoPath: string): Promise<string[]>;
25
+ /**
26
+ * Gets tracked file paths from the index (reflects working tree state, even during rebase).
27
+ * `paths` limits the read to those repo-relative folders (or files), matched literally rather than as globs;
28
+ * an empty array answers empty without running git, and omitting it reads the whole index.
29
+ */
30
+ getTrackedFiles(repoPath: string, options?: {
31
+ paths?: readonly string[];
32
+ }, cancellation?: AbortSignal): Promise<string[]>;
27
33
  getTreeEntryForRevision(repoPath: string, path: string, rev: string): Promise<GitTreeEntry | undefined>;
28
- getTreeForRevision(repoPath: string, rev: string): Promise<GitTreeEntry[]>;
34
+ /**
35
+ * Lists every entry (files and folders) of the tree at `rev`, recursively.
36
+ * `paths` limits the listing to those repo-relative folders (or files), matched literally rather than as globs;
37
+ * each scope's ancestor folders are listed too, an empty array answers empty without running git, and omitting
38
+ * it lists the whole tree.
39
+ */
40
+ getTreeForRevision(repoPath: string, rev: string, options?: {
41
+ paths?: readonly string[];
42
+ }): Promise<GitTreeEntry[]>;
29
43
  resolveRevision(repoPath: string, ref: string, pathOrUri?: string | Uri,
30
44
  /** `force`: skips the cached answer and any in-flight read that started before this call, and stores the fresh answer. */
31
45
  options?: {
@@ -39,8 +39,14 @@ export interface GitStatusSubProvider {
39
39
  hasConflictingFiles(repoPath: string, cancellation?: AbortSignal): Promise<boolean>;
40
40
  /** Rejects when git fails, rather than answering empty */
41
41
  getConflictingFiles(repoPath: string, cancellation?: AbortSignal): Promise<GitConflictFile[]>;
42
- /** Rejects when git fails, rather than answering empty */
43
- getUntrackedFiles(repoPath: string, cancellation?: AbortSignal): Promise<GitFile[]>;
42
+ /**
43
+ * Rejects when git fails, rather than answering empty.
44
+ * `paths` limits the read to repo-relative files or folders (matched literally, never as globs); an empty
45
+ * array answers empty without running git, and omitting it reads the whole working tree.
46
+ */
47
+ getUntrackedFiles(repoPath: string, options?: {
48
+ paths?: readonly string[];
49
+ }, cancellation?: AbortSignal): Promise<GitFile[]>;
44
50
  }
45
51
  //#endregion
46
52
  //# sourceMappingURL=status.d.ts.map