@gitkraken/core-gitlens 0.13.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 (67) hide show
  1. package/CHANGELOG.md +23 -2
  2. package/dist/git/features.d.ts +1 -1
  3. package/dist/git/features.js +1 -0
  4. package/dist/git/features.js.map +1 -1
  5. package/dist/git/models/branch.d.ts +5 -0
  6. package/dist/git/models/branch.js +1 -1
  7. package/dist/git/models/branch.js.map +1 -1
  8. package/dist/git/models/reference.d.ts +3 -0
  9. package/dist/git/models/status.js +1 -1
  10. package/dist/git/parsers/diffParser.js +1 -1
  11. package/dist/git/providers/operations.d.ts +3 -2
  12. package/dist/git/providers/provider.d.ts +15 -4
  13. package/dist/git/providers/revision.d.ts +17 -3
  14. package/dist/git/run.types.d.ts +12 -0
  15. package/dist/git/utils/branch.utils.d.ts +4 -1
  16. package/dist/git/utils/branch.utils.js +20 -5
  17. package/dist/git/utils/branch.utils.js.map +1 -1
  18. package/dist/git/utils/reference.utils.d.ts +1 -0
  19. package/dist/git/utils/reference.utils.js.map +1 -1
  20. package/dist/git-cli/cliGitProvider.d.ts +8 -2
  21. package/dist/git-cli/cliGitProvider.js +75 -13
  22. package/dist/git-cli/cliGitProvider.js.map +1 -1
  23. package/dist/git-cli/exec/git.d.ts +5 -0
  24. package/dist/git-cli/exec/git.js +28 -5
  25. package/dist/git-cli/exec/git.js.map +1 -1
  26. package/dist/git-cli/exec/indexLock.d.ts +3 -2
  27. package/dist/git-cli/exec/indexLock.js +16 -6
  28. package/dist/git-cli/exec/indexLock.js.map +1 -1
  29. package/dist/git-cli/parsers/blameParser.js +2 -2
  30. package/dist/git-cli/parsers/refParser.js +4 -2
  31. package/dist/git-cli/parsers/refParser.js.map +1 -1
  32. package/dist/git-cli/parsers/statusParser.d.ts +6 -0
  33. package/dist/git-cli/parsers/statusParser.js +33 -3
  34. package/dist/git-cli/parsers/statusParser.js.map +1 -1
  35. package/dist/git-cli/providers/branchRemote.d.ts +14 -0
  36. package/dist/git-cli/providers/branchRemote.js +36 -0
  37. package/dist/git-cli/providers/branchRemote.js.map +1 -0
  38. package/dist/git-cli/providers/branches.js +6 -3
  39. package/dist/git-cli/providers/branches.js.map +1 -1
  40. package/dist/git-cli/providers/commits.js +2 -2
  41. package/dist/git-cli/providers/config.js +2 -2
  42. package/dist/git-cli/providers/contributors.js +1 -1
  43. package/dist/git-cli/providers/graph.js +9 -6
  44. package/dist/git-cli/providers/graph.js.map +1 -1
  45. package/dist/git-cli/providers/operations.js +20 -16
  46. package/dist/git-cli/providers/operations.js.map +1 -1
  47. package/dist/git-cli/providers/pausedOperations.js +2 -2
  48. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  49. package/dist/git-cli/providers/revision.d.ts +6 -2
  50. package/dist/git-cli/providers/revision.js +38 -12
  51. package/dist/git-cli/providers/revision.js.map +1 -1
  52. package/dist/git-cli/providers/staging.js +1 -1
  53. package/dist/git-cli/providers/status.js +2 -2
  54. package/dist/ipc/discovery.js +1 -1
  55. package/dist/plus/agents/providers/claudeCodeTranscript.js +6 -6
  56. package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
  57. package/dist/plus/ai/providers/openAICompatibleProviderBase.js +1 -1
  58. package/dist/plus/git-github/providers/github/revision.d.ts +6 -2
  59. package/dist/plus/git-github/providers/github/revision.js +15 -10
  60. package/dist/plus/git-github/providers/github/revision.js.map +1 -1
  61. package/dist/plus/git-github/providers/github/status.js +1 -1
  62. package/dist/plus/integrations/providers/azure/azure.js +1 -1
  63. package/dist/plus/integrations/providers/azure/workItemStateCategories.d.ts +5 -0
  64. package/dist/plus/integrations/providers/azure/workItemStateCategories.js +5 -0
  65. package/dist/plus/integrations/providers/azure/workItemStateCategories.js.map +1 -1
  66. package/dist/utils/env/node/exec.js +2 -2
  67. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -6,6 +6,26 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.14.0] - 2026-10-18
10
+
11
+ ### Added
12
+
13
+ - Adds a `paths` option to `getTrackedFiles` and `getTreeForRevision`, and to `getIgnoredEntries` (see Changed), that limits the read to repo-relative folders or files, matched literally, so a host showing a file tree can load one folder at a time and git walks only that folder. An empty `paths` answers empty without running git; without `paths` each read is unchanged. `getTrackedFiles` also takes `cancellation`, and `getTreeForRevision` lists a scope's ancestor folders with it. The GitHub provider still lists only a tree's root, so there `paths` only filters that root listing (git, git-cli, plus/git-github)
14
+ - Adds a `beforeIndexLockRetry(lockError)` run option, also on `GitOperationRunOptions` (so `commit`, `reset`, `restore`, `checkout` and the other typed writes that take run options accept it), called before core retries an index write that found `index.lock` held by another process, after the wait and right before the next attempt. The index may have changed while the other process held the lock, so a host can re-check what the retry will act on, such as the staged set a `commit` records; rejecting gives up with that rejection as the run's failure in every `errors` mode, and throwing `lockError` back opts out of the retry. It must not write the index through core, and a run carrying it is never shared with an identical concurrent run (git, git-cli)
15
+
16
+ ### Changed
17
+
18
+ - Changes `getIgnoredEntries` to take `options?: { paths?: readonly string[]; priority?: GitCommandPriority }` before `cancellation`, the same shape as `getIgnoredPaths`. A host passing `cancellation` as the second argument must move it to the third (git, git-cli)
19
+ - Changes branch reads to report a local branch's upstream remote exactly, as `GitTrackingUpstream.remote` (and `remote` on a branch reference's `upstream`), from git's `%(upstream:remotename)` on Git 2.23+ at no extra cost. `GitBranch.remoteName`, `trackingWithoutRemote`, `getBranchNameAndRemote` and `getBranchTrackingWithoutRemote` prefer it, so a host renaming or deleting a branch's remote counterpart no longer parses the upstream itself; it is `undefined` for a local upstream and on older Git, where the first-`/` split remains. Remote-tracking branches (`refs/remotes/...`) are still split at the first `/`, since git has no remote to report for them (git, git-cli)
20
+ - Changes `getIgnoredPaths` to take `options?: { priority?: GitCommandPriority }` before `cancellation`, so a caller waiting on the answer (opening a file) can run it as `'interactive'`. A host passing `cancellation` as the third argument must move it to the fourth (git, git-cli)
21
+
22
+ ### Fixed
23
+
24
+ - Fixes an index-writing run being retried when the held `index.lock` was reported by something the run started rather than by git itself, such as a commit hook whose own `git add` lost the race, which re-ran the whole commit, hooks included: a run is now retried only when git's failure to take the lock is the first thing it printed (git-cli)
25
+ - Fixes `getIgnoredEntries` leaving out the ignored entries inside a new untracked folder (a `newpkg/node_modules/` or `newpkg/debug.log` beside an untracked `newpkg/index.ts`), which `git status --ignored` lists. It still lists with `ls-files`, and asks `git status --ignored` only about new untracked folders, without taking `index.lock`, so it never walks the whole repository's ignored trees (`node_modules/` and the like) the way a whole-repository `git status --ignored` does. On Git 2.16+ that `status` uses `--ignored=matching`, which reports a folder an ignore rule matches without walking it, and folds the result back to the same entries (git-cli)
26
+ - Fixes `push`, `fetch` with a branch, and a `fastForward: 'only'` `pull` of a branch checked out nowhere splitting an upstream such as `team/fork/feature` at its first `/`, so a remote whose own name contains a `/` was pushed to or fetched from as remote `team` and branch `fork/feature`: the remote is now the longest of the repository's remotes that prefixes the name, read only when the name leaves that ambiguous. The same applies to a branch's PR-base merge target and to remote branch tips in the graph. Adds `splitRemoteBranchName(name, remoteNames)` (git, git-cli)
27
+ - Fixes `getIgnoredPaths` reading each path as a pathspec, so a file named `:secret` was answered as `secret` (and reported ignored when `secret` is): a path starting with `:` is now checked as that exact file and comes back in the caller's spelling (git-cli)
28
+
9
29
  ## [0.13.0] - 2026-10-18
10
30
 
11
31
  ### Added
@@ -48,7 +68,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
48
68
 
49
69
  ### Fixed
50
70
 
51
- - Fixes Azure DevOps Services and Server issue lists omitting Removed or Completed work items without closure dates. State filters now reach project and account-wide reads, and workflow metadata is shared with identity and presentation reads ([#6013](https://github.com/gitkraken/vscode-gitlens/issues/6013)) (plus/integrations)
71
+ - Fixes Azure DevOps Services and Server issue lists omitting Removed or Completed work items without closure dates. State filters now reach project and account-wide reads, and workflow metadata is shared with identity and presentation reads. The metadata is kept for 5 minutes per project, work item type and token; a failed metadata read is kept for 30 seconds, so reads in that window fail with the same error before the next one retries ([#6013](https://github.com/gitkraken/vscode-gitlens/issues/6013)) (plus/integrations)
52
72
  - Fixes `listIssueTrackerIssuesPage` publishing no warning for a Jira project, or a relationship of a user-scoped Jira read, cut short by the page backstop when the read also failed, which an issue another project or relationship couldn't read is enough for: the skipped issue then stood for the whole gap. The cut is now reported for its project whatever else failed. A Jira issue that can't be read is no longer published as an authentication, rate-limit or not-found failure, nor as an unreachable server, when its own error names an HTTP status ([#6011](https://github.com/gitkraken/vscode-gitlens/issues/6011)) (plus/integrations)
53
73
  - Fixes Azure DevOps remotes in the legacy `{org}.visualstudio.com/DefaultCollection/{project}/_git/{repo}` form (any casing of `DefaultCollection`) having no `providerDesc` and a `repoDesc.name` that kept the collection segment, so every pull request, work item and commit author read threw `Invalid Azure repository descriptor`. The provider now maps them to `owner: '{org}'` and `name: '{project}/_git/{repo}'`. Remotes with no project segment (`{org}.visualstudio.com/DefaultCollection/_git/{repo}`, `{org}.visualstudio.com/_git/{repo}` and `dev.azure.com/{org}/_git/{repo}`) resolve with the project named after the repository, and their `#` work item autolink points at the organization rather than a malformed URL. `parseAzureHttpsUrl` follows the same rules and returns percent-decoded names; it now also throws for a URL with segments after the repository name (a pull request page, for one), which its unanchored match used to accept; `getAzurePullRequestIdentityFromMaybeUrl` now reads a pasted dev.azure.com or visualstudio.com pull request URL with that same parser (so the legacy and project-less forms resolve, `_git` matches in any casing, and a dev.azure.com URL with more than an organization and a project before `_git` no longer resolves); Server URLs keep their own rules ([#5999](https://github.com/gitkraken/vscode-gitlens/issues/5999)) (git, plus/integrations)
54
74
  - Fixes Azure DevOps Server repository scopes a consumer parsed from a remote cloned without the project segment behind a virtual directory (`{vdir}/{collection}/_git/{repo}`), named as collection `{vdir}` and project `{collection}`, reading nothing: the repo-scoped pull request and issue reads (`listPullRequestsPage`, `listIssuesPage`), `searchPullRequestsPage` / `searchIssuesPage` and their counts, `getPullRequestsForBranches` and the pull request and issue batch and etag reads were refused or answered 400 "A project name is required in order to reference a Git repository by name". The integration now settles such a scope against the collections it discovers, as it settles a remote's own descriptor since #6000 ([#6009](https://github.com/gitkraken/vscode-gitlens/issues/6009)) (plus/integrations)
@@ -730,7 +750,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
730
750
 
731
751
  - Initial release. Bundles `@gitlens/utils`, `@gitlens/git`, `@gitlens/git-cli`, `@gitlens/ai`, and `@gitlens/git-github` into a single core npm package with subpath exports.
732
752
 
733
- [unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.13.0...HEAD
753
+ [unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.14.0...HEAD
754
+ [0.14.0]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.13.0...gitkraken:releases/core/v0.14.0
734
755
  [0.13.0]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.12.0...gitkraken:releases/core/v0.13.0
735
756
  [0.12.0]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.11.1...gitkraken:releases/core/v0.12.0
736
757
  [0.11.1]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.11.0...gitkraken:releases/core/v0.11.1
@@ -1,5 +1,5 @@
1
1
  //#region ../git/src/features.d.ts
2
- export type GitFeatures = 'git:checkout:pathspec-from-file' | 'git:commit-graph' | 'git:commit-graph:changed-paths' | 'git:fetch:all-config' | 'git:fetch:follow-remote-head' | 'git:fetch:no-write-fetch-head' | 'git:for-each-ref:ahead-behind' | 'git:for-each-ref:worktreePath' | 'git:fsmonitor' | 'git:fsmonitor:linux' | 'git:ignoreRevsFile' | 'git:index:skipHash' | 'git:maintenance' | 'git:maintenance:pack-refs' | 'git:maintenance:start' | 'git:maintenance:start:systemd' | 'git:manyFiles' | 'git:merge-tree:merge-base' | 'git:merge-tree:write-tree' | 'git:patch-id:binary-oids' | 'git:patch-id:verbatim' | 'git:push:force-if-includes' | 'git:rebase:autosquash' | 'git:rev-parse:end-of-options' | 'git:signing:ssh' | 'git:signing:x509' | 'git:sparse-index' | 'git:stash:push:pathspecs' | 'git:stash:push:staged' | 'git:stash:push:stdin' | 'git:status:find-renames' | 'git:status:porcelain-v2' | 'git:untrackedCache' | 'git:worktree:list:lock-reason' | 'git:worktrees';
2
+ export type GitFeatures = 'git:checkout:pathspec-from-file' | 'git:commit-graph' | 'git:commit-graph:changed-paths' | 'git:fetch:all-config' | 'git:fetch:follow-remote-head' | 'git:fetch:no-write-fetch-head' | 'git:for-each-ref:ahead-behind' | 'git:for-each-ref:worktreePath' | 'git:fsmonitor' | 'git:fsmonitor:linux' | 'git:ignoreRevsFile' | 'git:index:skipHash' | 'git:maintenance' | 'git:maintenance:pack-refs' | 'git:maintenance:start' | 'git:maintenance:start:systemd' | 'git:manyFiles' | 'git:merge-tree:merge-base' | 'git:merge-tree:write-tree' | 'git:patch-id:binary-oids' | 'git:patch-id:verbatim' | 'git:push:force-if-includes' | 'git:rebase:autosquash' | 'git:rev-parse:end-of-options' | 'git:signing:ssh' | 'git:signing:x509' | 'git:sparse-index' | 'git:stash:push:pathspecs' | 'git:stash:push:staged' | 'git:stash:push:stdin' | 'git:status:find-renames' | 'git:status:ignored-matching' | 'git:status:porcelain-v2' | 'git:untrackedCache' | 'git:worktree:list:lock-reason' | 'git:worktrees';
3
3
  type ExtractPrefix<T> = T extends `${infer Prefix}:${infer Rest}` ? Rest extends `${infer SubPrefix}:${string}` ? T | `${Prefix}:${SubPrefix}` | Prefix : T | Prefix : never;
4
4
  export type GitFeatureOrPrefix = ExtractPrefix<GitFeatures>;
5
5
  export type FilteredGitFeatures<T extends GitFeatureOrPrefix> = T extends GitFeatures ? T : Extract<GitFeatures, T | `${T}:${string}`>;
@@ -32,6 +32,7 @@ const gitFeaturesByVersion = /* @__PURE__ */ new Map([
32
32
  ["git:stash:push:staged", "2.35.0"],
33
33
  ["git:stash:push:stdin", "2.30.0"],
34
34
  ["git:status:find-renames", "2.18"],
35
+ ["git:status:ignored-matching", "2.16"],
35
36
  ["git:status:porcelain-v2", "2.11"],
36
37
  ["git:untrackedCache", "2.8"],
37
38
  ["git:worktree:list:lock-reason", "2.31"],
@@ -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: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: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['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":";AAiDA,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;CAClC,CAAC,2BAA2B,MAAM;CAElC,CAAC,sBAAsB,KAAK;CAE5B,CAAC,iCAAiC,MAAM;CACxC,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"}
@@ -88,6 +88,11 @@ export interface GitTrackingState {
88
88
  }
89
89
  export interface GitTrackingUpstream {
90
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;
91
96
  readonly missing: boolean;
92
97
  readonly state: GitTrackingState;
93
98
  }
@@ -107,7 +107,7 @@ let GitBranch = _GitBranch = class GitBranch {
107
107
  }
108
108
  get remoteName() {
109
109
  if (this.remote) return getRemoteNameFromBranchName(this.name);
110
- if (this.upstream != null) return getRemoteNameFromBranchName(this.upstream.name);
110
+ if (this.upstream != null) return this.upstream.remote ?? getRemoteNameFromBranchName(this.upstream.name);
111
111
  }
112
112
  get starred() {
113
113
  return this.metadata?.disposition === "starred";
@@ -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\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 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
@@ -3,8 +3,8 @@ import { memoize } from "../../utils/decorators/memoize.js";
3
3
  import { formatDetachedHeadName, isDetachedHead } from "../utils/branch.utils.js";
4
4
  import __decorate from "../../_virtual/@oxc-project+runtime/helpers/esm/decorate.js";
5
5
  import { serializable } from "../../utils/decorators/serializable.js";
6
- import { GitFileConflictStatus, GitFileIndexStatus, GitFileWorkingTreeStatus } from "./fileStatus.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 {
@@ -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+))? @@/;
@@ -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,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";
@@ -58,15 +59,25 @@ export interface GitProvider {
58
59
  * them: an ignored file is one entry, and a directory whose entire contents are ignored is one entry with a
59
60
  * trailing `/` (its contents aren't listed). Empty directories and `.git/` aren't listed. Sorted, and not capped —
60
61
  * the caller limits what it shows. Unlike `getIgnoredDirectories` this is a listing, not a watcher-pruning set, so
61
- * nothing is dropped or re-confirmed against the rules.
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.
62
66
  */
63
- getIgnoredEntries?(repoPath: string, cancellation?: AbortSignal): Promise<string[]>;
67
+ getIgnoredEntries?(repoPath: string, options?: {
68
+ paths?: readonly string[];
69
+ priority?: GitCommandPriority;
70
+ }, cancellation?: AbortSignal): Promise<string[]>;
64
71
  /**
65
72
  * An exact check of which of `paths` (repo-relative) git's ignore rules match — the subset that is ignored, as
66
73
  * given. A tracked file isn't reported as ignored, even when a rule matches it. This is git's answer, where the
67
- * in-memory `GitIgnoreFilter` errs toward not-ignored.
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.
68
77
  */
69
- getIgnoredPaths?(repoPath: string, paths: readonly string[], cancellation?: AbortSignal): Promise<Set<string>>;
78
+ getIgnoredPaths?(repoPath: string, paths: readonly string[], options?: {
79
+ priority?: GitCommandPriority;
80
+ }, cancellation?: AbortSignal): Promise<Set<string>>;
70
81
  getIgnoredUrisFilter?(repoPath: string): Promise<(uri: Uri) => boolean>;
71
82
  getLastFetchedTimestamp?(repoPath: string): Promise<number | undefined>;
72
83
  /**
@@ -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?: {
@@ -91,6 +91,18 @@ export interface GitRunOptions {
91
91
  configs?: readonly string[];
92
92
  readonly correlationKey?: string;
93
93
  errors?: GitErrorHandling;
94
+ /**
95
+ * Called before core retries a write that found `index.lock` held by another process — after the wait, right
96
+ * before the next attempt. The index may have changed while the other process held the lock, so this lets the
97
+ * caller re-check what the retry will act on (e.g. the staged set a `commit` records). Rejecting gives up: the
98
+ * rejection becomes the run's failure, in every `errors` mode. Throwing `lockError` back opts out of the retry,
99
+ * leaving the lock failure as the result.
100
+ *
101
+ * It runs while this checkout's index writes are held in order, so it must not write the index through core
102
+ * (it would wait on itself). A run given this hook is never shared with an identical concurrent run. Only the
103
+ * index-lock retry calls it, not the config-lock retry.
104
+ */
105
+ beforeIndexLockRetry?: (lockError: Error) => void | Promise<void>;
94
106
  /**
95
107
  * Non-zero exit codes that are answers rather than failures (e.g. `1` from `diff --quiet`, "has differences");
96
108
  * a listed code resolves as `exited` with that `exitCode` in every `errors` mode.
@@ -5,6 +5,8 @@ import { BranchMetadata, BranchMetadataGkConfigKey, GitBranch, GitTrackingUpstre
5
5
  export declare function formatDetachedHeadName(sha: string): string;
6
6
  export declare function getBranchNameAndRemote(ref: GitBranchReference): [name: string, remote: string | undefined];
7
7
  export declare function getBranchTrackingWithoutRemote(ref: GitBranchReference): string | undefined;
8
+ /** Splits `name` at the longest of `remoteNames` that prefixes it, so a remote whose own name contains a `/` resolves whole */
9
+ export declare function splitRemoteBranchName(name: string, remoteNames: Iterable<string>): [remote: string, branch: string] | undefined;
8
10
  export declare function isDetachedHead(name: string): boolean;
9
11
  export declare function isOfBranchRefType(branch: GitReference | undefined): branch is GitBranchReference;
10
12
  export declare function isRemoteBranch(refName: string): boolean;
@@ -15,7 +17,8 @@ export declare function parseRefName(refName: string): {
15
17
  };
16
18
  export declare function getLocalBranchByUpstream(remoteBranchName: string, branches: PageableResult<GitBranch> | ReadonlyMap<unknown, GitBranch>): Promise<GitBranch | undefined>;
17
19
  export declare function getLocalBranchUpstreamNames(branches: PageableResult<GitBranch>): Promise<Set<string>>;
18
- export declare function parseUpstream(upstream: string, tracking: string): GitTrackingUpstream | undefined;
20
+ /** @param remote - `%(upstream:remotename)`; empty or `.` (a local upstream) is not a remote */
21
+ export declare function parseUpstream(upstream: string, tracking: string, remote?: string): GitTrackingUpstream | undefined;
19
22
  /** Splits a `branch.<name>.<key>` gk config key that a branch's {@link BranchMetadata} is read from, or `undefined` for any other key */
20
23
  export declare function parseBranchMetadataGkConfigKey(key: string): {
21
24
  branch: string;
@@ -22,6 +22,7 @@ function getBranchNameAndRemote(ref) {
22
22
  if (index === -1) return [ref.name, void 0];
23
23
  return [ref.name.substring(index + 1), ref.name.substring(0, index)];
24
24
  }
25
+ if (ref.upstream?.remote) return [ref.name, ref.upstream.remote];
25
26
  if (ref.upstream?.name != null) {
26
27
  const index = getRemoteNameSlashIndex(ref.upstream.name);
27
28
  if (index === -1) return [ref.name, void 0];
@@ -30,7 +31,17 @@ function getBranchNameAndRemote(ref) {
30
31
  return [ref.name, void 0];
31
32
  }
32
33
  function getBranchTrackingWithoutRemote(ref) {
33
- return ref.upstream?.name.substring(getRemoteNameSlashIndex(ref.upstream.name) + 1);
34
+ if (ref.upstream == null) return void 0;
35
+ const { name, remote } = ref.upstream;
36
+ if (remote && name.startsWith(`${remote}/`)) return name.substring(remote.length + 1);
37
+ return name.substring(getRemoteNameSlashIndex(name) + 1);
38
+ }
39
+ /** Splits `name` at the longest of `remoteNames` that prefixes it, so a remote whose own name contains a `/` resolves whole */
40
+ function splitRemoteBranchName(name, remoteNames) {
41
+ if (name.startsWith("remotes/")) name = name.substring(8);
42
+ let match;
43
+ for (const remote of remoteNames) if (name.length > remote.length + 1 && name.charCodeAt(remote.length) === 47 && name.startsWith(remote) && (match == null || remote.length > match.length)) match = remote;
44
+ return match != null ? [match, name.substring(match.length + 1)] : void 0;
34
45
  }
35
46
  function isDetachedHead(name) {
36
47
  name = name.trim();
@@ -78,9 +89,11 @@ async function getLocalBranchUpstreamNames(branches) {
78
89
  return remoteBranches;
79
90
  }
80
91
  const trackingStateRegex = /(?:\[(?:ahead ([0-9]+))?[,\s]*(?:behind ([0-9]+))?]|\[(gone)])/;
81
- function parseUpstream(upstream, tracking) {
92
+ /** @param remote - `%(upstream:remotename)`; empty or `.` (a local upstream) is not a remote */
93
+ function parseUpstream(upstream, tracking, remote) {
82
94
  if (!upstream) return void 0;
83
95
  const { name } = parseRefName(upstream);
96
+ const remoteProp = remote && remote !== "." ? { remote } : void 0;
84
97
  const match = trackingStateRegex.exec(tracking);
85
98
  if (match == null) return {
86
99
  name,
@@ -88,7 +101,8 @@ function parseUpstream(upstream, tracking) {
88
101
  state: {
89
102
  ahead: 0,
90
103
  behind: 0
91
- }
104
+ },
105
+ ...remoteProp
92
106
  };
93
107
  const ahead = match[1] == null ? 0 : Number(match[1]);
94
108
  const behind = match[2] == null ? 0 : Number(match[2]);
@@ -98,7 +112,8 @@ function parseUpstream(upstream, tracking) {
98
112
  state: {
99
113
  ahead: isNaN(ahead) ? 0 : ahead,
100
114
  behind: isNaN(behind) ? 0 : behind
101
- }
115
+ },
116
+ ...remoteProp
102
117
  };
103
118
  }
104
119
  const branchMetadataGkConfigKeyRegex = /^branch\.(.+)\.(gk-(?:last-accessed|last-modified|agent-last-activity|disposition))$/;
@@ -131,6 +146,6 @@ function setBranchMetadataValue(metadata, key, value) {
131
146
  }
132
147
  }
133
148
  //#endregion
134
- export { formatDetachedHeadName, getBranchNameAndRemote, getBranchTrackingWithoutRemote, getLocalBranchByUpstream, getLocalBranchUpstreamNames, isDetachedHead, isOfBranchRefType, isRemoteBranch, isRemoteHEAD, parseBranchMetadataGkConfigKey, parseRefName, parseUpstream, setBranchMetadataValue };
149
+ export { formatDetachedHeadName, getBranchNameAndRemote, getBranchTrackingWithoutRemote, getLocalBranchByUpstream, getLocalBranchUpstreamNames, isDetachedHead, isOfBranchRefType, isRemoteBranch, isRemoteHEAD, parseBranchMetadataGkConfigKey, parseRefName, parseUpstream, setBranchMetadataValue, splitRemoteBranchName };
135
150
 
136
151
  //# sourceMappingURL=branch.utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"branch.utils.js","names":[],"sources":["../../../../git/src/utils/branch.utils.ts"],"sourcesContent":["import { getRemoteNameSlashIndex } from '@gitlens/utils/gitRefs.js';\nimport type { PageableResult } from '@gitlens/utils/paging.js';\nimport type { BranchMetadata, BranchMetadataGkConfigKey, GitBranch, GitTrackingUpstream } from '../models/branch.js';\nimport type { GitBranchReference, GitReference } from '../models/reference.js';\nimport { shortenRevision } from './revision.utils.js';\n\n/**\n * The names git uses where a branch name would go when HEAD isn't on a branch — `(HEAD detached\n * at|from <rev>)`, `(no branch)`, `(no branch, rebasing <name>)`, `(no branch, bisect started on\n * <name>)`, and `git status --porcelain=v2`'s `branch.head` token `(detached)` — plus bare `HEAD`\n * and our own {@link formatDetachedHeadName} output (`(<rev>...)`).\n *\n * Deliberately NOT \"anything parenthesized\": parentheses are legal in ref names, so `(release)`,\n * `v1.0(rc)` and `feat/(wip)` are all real branches a user can be on. Matching those made\n * `GitBranch` rewrite a genuine branch's `name` to the synthesized `(sha…)` label and re-key its\n * `id` by SHA, which corrupts its identity for every downstream consumer.\n */\nconst detachedHEADRegex = /^(?:HEAD|\\(detached\\)|\\(HEAD detached (?:at|from) .+\\)|\\(no branch.*\\)|\\(.+\\.\\.\\.\\))$/;\n\nexport function formatDetachedHeadName(sha: string): string {\n\treturn `(${shortenRevision(sha)}...)`;\n}\n\nexport function getBranchNameAndRemote(ref: GitBranchReference): [name: string, remote: string | undefined] {\n\tif (ref.remote) {\n\t\tconst index = getRemoteNameSlashIndex(ref.name);\n\t\tif (index === -1) return [ref.name, undefined];\n\n\t\treturn [ref.name.substring(index + 1), ref.name.substring(0, index)];\n\t}\n\n\tif (ref.upstream?.name != null) {\n\t\tconst index = getRemoteNameSlashIndex(ref.upstream.name);\n\t\tif (index === -1) return [ref.name, undefined];\n\n\t\treturn [ref.name, ref.upstream.name.substring(0, index)];\n\t}\n\n\treturn [ref.name, undefined];\n}\n\nexport function getBranchTrackingWithoutRemote(ref: GitBranchReference): string | undefined {\n\treturn ref.upstream?.name.substring(getRemoteNameSlashIndex(ref.upstream.name) + 1);\n}\n\nexport function isDetachedHead(name: string): boolean {\n\t// If there is whitespace in the name assume this is not a valid branch name\n\t// Deals with detached HEAD states\n\tname = name.trim();\n\treturn name.length ? detachedHEADRegex.test(name) : true;\n}\n\nexport function isOfBranchRefType(branch: GitReference | undefined): branch is GitBranchReference {\n\treturn branch?.refType === 'branch';\n}\n\nconst localBranchesPrefixRegex = /^(refs\\/)?heads\\//i;\nconst remoteBranchesPrefixRegex = /^(refs\\/)?remotes\\//i;\nconst remoteHEADRegex = /^(refs\\/)?remotes\\/(.*\\/)HEAD$/i;\n\nexport function isRemoteBranch(refName: string): boolean {\n\treturn remoteBranchesPrefixRegex.test(refName);\n}\n\nexport function isRemoteHEAD(refName: string): boolean {\n\treturn remoteHEADRegex.test(refName);\n}\n\nexport function parseRefName(refName: string): { name: string; remote: boolean } {\n\tconst remote = isRemoteBranch(refName);\n\n\tlet name;\n\tif (remote) {\n\t\t// Strip off refs/remotes/\n\t\tname = refName.replace(remoteBranchesPrefixRegex, '');\n\t} else {\n\t\t// Strip off refs/heads/\n\t\tname = refName.replace(localBranchesPrefixRegex, '');\n\t}\n\n\treturn { name: name, remote: remote };\n}\n\nexport async function getLocalBranchByUpstream(\n\tremoteBranchName: string,\n\tbranches: PageableResult<GitBranch> | ReadonlyMap<unknown, GitBranch>,\n): Promise<GitBranch | undefined> {\n\tlet qualifiedRemoteBranchName;\n\tif (remoteBranchName.startsWith('remotes/')) {\n\t\tqualifiedRemoteBranchName = remoteBranchName;\n\t\tremoteBranchName = remoteBranchName.substring(8);\n\t} else {\n\t\tqualifiedRemoteBranchName = `remotes/${remoteBranchName}`;\n\t}\n\n\tfunction matches(branch: GitBranch): boolean {\n\t\treturn (\n\t\t\t!branch.remote &&\n\t\t\tbranch.upstream?.name != null &&\n\t\t\t(branch.upstream.name === remoteBranchName || branch.upstream.name === qualifiedRemoteBranchName!)\n\t\t);\n\t}\n\n\tconst values = branches.values();\n\tif (Symbol.asyncIterator in values) {\n\t\tfor await (const branch of values) {\n\t\t\tif (matches(branch)) return branch;\n\t\t}\n\t} else {\n\t\tfor (const branch of values) {\n\t\t\tif (matches(branch)) return branch;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nexport async function getLocalBranchUpstreamNames(branches: PageableResult<GitBranch>): Promise<Set<string>> {\n\tconst remoteBranches = new Set<string>();\n\n\tfor await (const branch of branches.values()) {\n\t\tif (!branch.remote && branch.upstream?.name != null) {\n\t\t\tremoteBranches.add(branch.upstream.name);\n\t\t}\n\t}\n\n\treturn remoteBranches;\n}\n\nconst trackingStateRegex = /(?:\\[(?:ahead ([0-9]+))?[,\\s]*(?:behind ([0-9]+))?]|\\[(gone)])/;\n\nexport function parseUpstream(upstream: string, tracking: string): GitTrackingUpstream | undefined {\n\tif (!upstream) return undefined;\n\n\tconst { name } = parseRefName(upstream);\n\n\tconst match = trackingStateRegex.exec(tracking);\n\tif (match == null) {\n\t\treturn { name: name, missing: false, state: { ahead: 0, behind: 0 } };\n\t}\n\n\tconst ahead = match[1] == null ? 0 : Number(match[1]);\n\tconst behind = match[2] == null ? 0 : Number(match[2]);\n\n\treturn {\n\t\tname: name,\n\t\tmissing: match[3] != null,\n\t\tstate: { ahead: isNaN(ahead) ? 0 : ahead, behind: isNaN(behind) ? 0 : behind },\n\t};\n}\n\nconst branchMetadataGkConfigKeyRegex =\n\t/^branch\\.(.+)\\.(gk-(?:last-accessed|last-modified|agent-last-activity|disposition))$/;\n\n/** Splits a `branch.<name>.<key>` gk config key that a branch's {@link BranchMetadata} is read from, or `undefined` for any other key */\nexport function parseBranchMetadataGkConfigKey(\n\tkey: string,\n): { branch: string; key: BranchMetadataGkConfigKey } | undefined {\n\tconst match = branchMetadataGkConfigKeyRegex.exec(key);\n\tif (match == null) return undefined;\n\n\treturn { branch: match[1], key: match[2] as BranchMetadataGkConfigKey };\n}\n\n/** Sets the field `key` is read into to `value`, or removes it for `undefined`, exactly as a fresh read of the key would */\nexport function setBranchMetadataValue(\n\tmetadata: BranchMetadata,\n\tkey: BranchMetadataGkConfigKey,\n\tvalue: string | undefined,\n): void {\n\tswitch (key) {\n\t\tcase 'gk-last-accessed':\n\t\t\tif (value != null) {\n\t\t\t\tmetadata.lastAccessedAt = value;\n\t\t\t} else {\n\t\t\t\tdelete metadata.lastAccessedAt;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'gk-last-modified':\n\t\t\tif (value != null) {\n\t\t\t\tmetadata.lastModifiedAt = value;\n\t\t\t} else {\n\t\t\t\tdelete metadata.lastModifiedAt;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'gk-agent-last-activity':\n\t\t\tif (value != null) {\n\t\t\t\tmetadata.agentLastActivityAt = value;\n\t\t\t} else {\n\t\t\t\tdelete metadata.agentLastActivityAt;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'gk-disposition':\n\t\t\tif (value === 'starred' || value === 'archived') {\n\t\t\t\tmetadata.disposition = value;\n\t\t\t} else {\n\t\t\t\tdelete metadata.disposition;\n\t\t\t}\n\t\t\tbreak;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;AAiBA,MAAM,oBAAoB;AAE1B,SAAgB,uBAAuB,KAAqB;CAC3D,OAAO,IAAI,gBAAgB,GAAG,EAAE;AACjC;AAEA,SAAgB,uBAAuB,KAAqE;CAC3G,IAAI,IAAI,QAAQ;EACf,MAAM,QAAQ,wBAAwB,IAAI,IAAI;EAC9C,IAAI,UAAU,IAAI,OAAO,CAAC,IAAI,MAAM,KAAA,CAAS;EAE7C,OAAO,CAAC,IAAI,KAAK,UAAU,QAAQ,CAAC,GAAG,IAAI,KAAK,UAAU,GAAG,KAAK,CAAC;CACpE;CAEA,IAAI,IAAI,UAAU,QAAQ,MAAM;EAC/B,MAAM,QAAQ,wBAAwB,IAAI,SAAS,IAAI;EACvD,IAAI,UAAU,IAAI,OAAO,CAAC,IAAI,MAAM,KAAA,CAAS;EAE7C,OAAO,CAAC,IAAI,MAAM,IAAI,SAAS,KAAK,UAAU,GAAG,KAAK,CAAC;CACxD;CAEA,OAAO,CAAC,IAAI,MAAM,KAAA,CAAS;AAC5B;AAEA,SAAgB,+BAA+B,KAA6C;CAC3F,OAAO,IAAI,UAAU,KAAK,UAAU,wBAAwB,IAAI,SAAS,IAAI,IAAI,CAAC;AACnF;AAEA,SAAgB,eAAe,MAAuB;CAGrD,OAAO,KAAK,KAAK;CACjB,OAAO,KAAK,SAAS,kBAAkB,KAAK,IAAI,IAAI;AACrD;AAEA,SAAgB,kBAAkB,QAAgE;CACjG,OAAO,QAAQ,YAAY;AAC5B;AAEA,MAAM,2BAA2B;AACjC,MAAM,4BAA4B;AAClC,MAAM,kBAAkB;AAExB,SAAgB,eAAe,SAA0B;CACxD,OAAO,0BAA0B,KAAK,OAAO;AAC9C;AAEA,SAAgB,aAAa,SAA0B;CACtD,OAAO,gBAAgB,KAAK,OAAO;AACpC;AAEA,SAAgB,aAAa,SAAoD;CAChF,MAAM,SAAS,eAAe,OAAO;CAErC,IAAI;CACJ,IAAI,QAEH,OAAO,QAAQ,QAAQ,2BAA2B,EAAE;MAGpD,OAAO,QAAQ,QAAQ,0BAA0B,EAAE;CAGpD,OAAO;EAAQ;EAAc;CAAO;AACrC;AAEA,eAAsB,yBACrB,kBACA,UACiC;CACjC,IAAI;CACJ,IAAI,iBAAiB,WAAW,UAAU,GAAG;EAC5C,4BAA4B;EAC5B,mBAAmB,iBAAiB,UAAU,CAAC;CAChD,OACC,4BAA4B,WAAW;CAGxC,SAAS,QAAQ,QAA4B;EAC5C,OACC,CAAC,OAAO,UACR,OAAO,UAAU,QAAQ,SACxB,OAAO,SAAS,SAAS,oBAAoB,OAAO,SAAS,SAAS;CAEzE;CAEA,MAAM,SAAS,SAAS,OAAO;CAC/B,IAAI,OAAO,iBAAiB,QAChB;aAAA,MAAM,UAAU,QAC1B,IAAI,QAAQ,MAAM,GAAG,OAAO;CAAA,OAG7B,KAAK,MAAM,UAAU,QACpB,IAAI,QAAQ,MAAM,GAAG,OAAO;AAK/B;AAEA,eAAsB,4BAA4B,UAA2D;CAC5G,MAAM,iCAAiB,IAAI,IAAY;CAEvC,WAAW,MAAM,UAAU,SAAS,OAAO,GAC1C,IAAI,CAAC,OAAO,UAAU,OAAO,UAAU,QAAQ,MAC9C,eAAe,IAAI,OAAO,SAAS,IAAI;CAIzC,OAAO;AACR;AAEA,MAAM,qBAAqB;AAE3B,SAAgB,cAAc,UAAkB,UAAmD;CAClG,IAAI,CAAC,UAAU,OAAO,KAAA;CAEtB,MAAM,EAAE,SAAS,aAAa,QAAQ;CAEtC,MAAM,QAAQ,mBAAmB,KAAK,QAAQ;CAC9C,IAAI,SAAS,MACZ,OAAO;EAAQ;EAAM,SAAS;EAAO,OAAO;GAAE,OAAO;GAAG,QAAQ;EAAE;CAAE;CAGrE,MAAM,QAAQ,MAAM,MAAM,OAAO,IAAI,OAAO,MAAM,EAAE;CACpD,MAAM,SAAS,MAAM,MAAM,OAAO,IAAI,OAAO,MAAM,EAAE;CAErD,OAAO;EACA;EACN,SAAS,MAAM,MAAM;EACrB,OAAO;GAAE,OAAO,MAAM,KAAK,IAAI,IAAI;GAAO,QAAQ,MAAM,MAAM,IAAI,IAAI;EAAO;CAC9E;AACD;AAEA,MAAM,iCACL;;AAGD,SAAgB,+BACf,KACiE;CACjE,MAAM,QAAQ,+BAA+B,KAAK,GAAG;CACrD,IAAI,SAAS,MAAM,OAAO,KAAA;CAE1B,OAAO;EAAE,QAAQ,MAAM;EAAI,KAAK,MAAM;CAAgC;AACvE;;AAGA,SAAgB,uBACf,UACA,KACA,OACO;CACP,QAAQ,KAAR;EACC,KAAK;GACJ,IAAI,SAAS,MACZ,SAAS,iBAAiB;QAE1B,OAAO,SAAS;GAEjB;EACD,KAAK;GACJ,IAAI,SAAS,MACZ,SAAS,iBAAiB;QAE1B,OAAO,SAAS;GAEjB;EACD,KAAK;GACJ,IAAI,SAAS,MACZ,SAAS,sBAAsB;QAE/B,OAAO,SAAS;GAEjB;EACD,KAAK,kBACJ,IAAI,UAAU,aAAa,UAAU,YACpC,SAAS,cAAc;OAEvB,OAAO,SAAS;CAGnB;AACD"}
1
+ {"version":3,"file":"branch.utils.js","names":[],"sources":["../../../../git/src/utils/branch.utils.ts"],"sourcesContent":["import { getRemoteNameSlashIndex } from '@gitlens/utils/gitRefs.js';\nimport type { PageableResult } from '@gitlens/utils/paging.js';\nimport type { BranchMetadata, BranchMetadataGkConfigKey, GitBranch, GitTrackingUpstream } from '../models/branch.js';\nimport type { GitBranchReference, GitReference } from '../models/reference.js';\nimport { shortenRevision } from './revision.utils.js';\n\n/**\n * The names git uses where a branch name would go when HEAD isn't on a branch — `(HEAD detached\n * at|from <rev>)`, `(no branch)`, `(no branch, rebasing <name>)`, `(no branch, bisect started on\n * <name>)`, and `git status --porcelain=v2`'s `branch.head` token `(detached)` — plus bare `HEAD`\n * and our own {@link formatDetachedHeadName} output (`(<rev>...)`).\n *\n * Deliberately NOT \"anything parenthesized\": parentheses are legal in ref names, so `(release)`,\n * `v1.0(rc)` and `feat/(wip)` are all real branches a user can be on. Matching those made\n * `GitBranch` rewrite a genuine branch's `name` to the synthesized `(sha…)` label and re-key its\n * `id` by SHA, which corrupts its identity for every downstream consumer.\n */\nconst detachedHEADRegex = /^(?:HEAD|\\(detached\\)|\\(HEAD detached (?:at|from) .+\\)|\\(no branch.*\\)|\\(.+\\.\\.\\.\\))$/;\n\nexport function formatDetachedHeadName(sha: string): string {\n\treturn `(${shortenRevision(sha)}...)`;\n}\n\nexport function getBranchNameAndRemote(ref: GitBranchReference): [name: string, remote: string | undefined] {\n\tif (ref.remote) {\n\t\tconst index = getRemoteNameSlashIndex(ref.name);\n\t\tif (index === -1) return [ref.name, undefined];\n\n\t\treturn [ref.name.substring(index + 1), ref.name.substring(0, index)];\n\t}\n\n\tif (ref.upstream?.remote) return [ref.name, ref.upstream.remote];\n\n\tif (ref.upstream?.name != null) {\n\t\tconst index = getRemoteNameSlashIndex(ref.upstream.name);\n\t\tif (index === -1) return [ref.name, undefined];\n\n\t\treturn [ref.name, ref.upstream.name.substring(0, index)];\n\t}\n\n\treturn [ref.name, undefined];\n}\n\nexport function getBranchTrackingWithoutRemote(ref: GitBranchReference): string | undefined {\n\tif (ref.upstream == null) return undefined;\n\n\tconst { name, remote } = ref.upstream;\n\tif (remote && name.startsWith(`${remote}/`)) return name.substring(remote.length + 1);\n\n\treturn name.substring(getRemoteNameSlashIndex(name) + 1);\n}\n\n/** Splits `name` at the longest of `remoteNames` that prefixes it, so a remote whose own name contains a `/` resolves whole */\nexport function splitRemoteBranchName(\n\tname: string,\n\tremoteNames: Iterable<string>,\n): [remote: string, branch: string] | undefined {\n\tif (name.startsWith('remotes/')) {\n\t\tname = name.substring(8);\n\t}\n\n\tlet match: string | undefined;\n\tfor (const remote of remoteNames) {\n\t\tif (\n\t\t\tname.length > remote.length + 1 &&\n\t\t\tname.charCodeAt(remote.length) === 47 /* '/' */ &&\n\t\t\tname.startsWith(remote) &&\n\t\t\t(match == null || remote.length > match.length)\n\t\t) {\n\t\t\tmatch = remote;\n\t\t}\n\t}\n\n\treturn match != null ? [match, name.substring(match.length + 1)] : undefined;\n}\n\nexport function isDetachedHead(name: string): boolean {\n\t// If there is whitespace in the name assume this is not a valid branch name\n\t// Deals with detached HEAD states\n\tname = name.trim();\n\treturn name.length ? detachedHEADRegex.test(name) : true;\n}\n\nexport function isOfBranchRefType(branch: GitReference | undefined): branch is GitBranchReference {\n\treturn branch?.refType === 'branch';\n}\n\nconst localBranchesPrefixRegex = /^(refs\\/)?heads\\//i;\nconst remoteBranchesPrefixRegex = /^(refs\\/)?remotes\\//i;\nconst remoteHEADRegex = /^(refs\\/)?remotes\\/(.*\\/)HEAD$/i;\n\nexport function isRemoteBranch(refName: string): boolean {\n\treturn remoteBranchesPrefixRegex.test(refName);\n}\n\nexport function isRemoteHEAD(refName: string): boolean {\n\treturn remoteHEADRegex.test(refName);\n}\n\nexport function parseRefName(refName: string): { name: string; remote: boolean } {\n\tconst remote = isRemoteBranch(refName);\n\n\tlet name;\n\tif (remote) {\n\t\t// Strip off refs/remotes/\n\t\tname = refName.replace(remoteBranchesPrefixRegex, '');\n\t} else {\n\t\t// Strip off refs/heads/\n\t\tname = refName.replace(localBranchesPrefixRegex, '');\n\t}\n\n\treturn { name: name, remote: remote };\n}\n\nexport async function getLocalBranchByUpstream(\n\tremoteBranchName: string,\n\tbranches: PageableResult<GitBranch> | ReadonlyMap<unknown, GitBranch>,\n): Promise<GitBranch | undefined> {\n\tlet qualifiedRemoteBranchName;\n\tif (remoteBranchName.startsWith('remotes/')) {\n\t\tqualifiedRemoteBranchName = remoteBranchName;\n\t\tremoteBranchName = remoteBranchName.substring(8);\n\t} else {\n\t\tqualifiedRemoteBranchName = `remotes/${remoteBranchName}`;\n\t}\n\n\tfunction matches(branch: GitBranch): boolean {\n\t\treturn (\n\t\t\t!branch.remote &&\n\t\t\tbranch.upstream?.name != null &&\n\t\t\t(branch.upstream.name === remoteBranchName || branch.upstream.name === qualifiedRemoteBranchName!)\n\t\t);\n\t}\n\n\tconst values = branches.values();\n\tif (Symbol.asyncIterator in values) {\n\t\tfor await (const branch of values) {\n\t\t\tif (matches(branch)) return branch;\n\t\t}\n\t} else {\n\t\tfor (const branch of values) {\n\t\t\tif (matches(branch)) return branch;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nexport async function getLocalBranchUpstreamNames(branches: PageableResult<GitBranch>): Promise<Set<string>> {\n\tconst remoteBranches = new Set<string>();\n\n\tfor await (const branch of branches.values()) {\n\t\tif (!branch.remote && branch.upstream?.name != null) {\n\t\t\tremoteBranches.add(branch.upstream.name);\n\t\t}\n\t}\n\n\treturn remoteBranches;\n}\n\nconst trackingStateRegex = /(?:\\[(?:ahead ([0-9]+))?[,\\s]*(?:behind ([0-9]+))?]|\\[(gone)])/;\n\n/** @param remote - `%(upstream:remotename)`; empty or `.` (a local upstream) is not a remote */\nexport function parseUpstream(upstream: string, tracking: string, remote?: string): GitTrackingUpstream | undefined {\n\tif (!upstream) return undefined;\n\n\tconst { name } = parseRefName(upstream);\n\tconst remoteProp = remote && remote !== '.' ? { remote: remote } : undefined;\n\n\tconst match = trackingStateRegex.exec(tracking);\n\tif (match == null) {\n\t\treturn { name: name, missing: false, state: { ahead: 0, behind: 0 }, ...remoteProp };\n\t}\n\n\tconst ahead = match[1] == null ? 0 : Number(match[1]);\n\tconst behind = match[2] == null ? 0 : Number(match[2]);\n\n\treturn {\n\t\tname: name,\n\t\tmissing: match[3] != null,\n\t\tstate: { ahead: isNaN(ahead) ? 0 : ahead, behind: isNaN(behind) ? 0 : behind },\n\t\t...remoteProp,\n\t};\n}\n\nconst branchMetadataGkConfigKeyRegex =\n\t/^branch\\.(.+)\\.(gk-(?:last-accessed|last-modified|agent-last-activity|disposition))$/;\n\n/** Splits a `branch.<name>.<key>` gk config key that a branch's {@link BranchMetadata} is read from, or `undefined` for any other key */\nexport function parseBranchMetadataGkConfigKey(\n\tkey: string,\n): { branch: string; key: BranchMetadataGkConfigKey } | undefined {\n\tconst match = branchMetadataGkConfigKeyRegex.exec(key);\n\tif (match == null) return undefined;\n\n\treturn { branch: match[1], key: match[2] as BranchMetadataGkConfigKey };\n}\n\n/** Sets the field `key` is read into to `value`, or removes it for `undefined`, exactly as a fresh read of the key would */\nexport function setBranchMetadataValue(\n\tmetadata: BranchMetadata,\n\tkey: BranchMetadataGkConfigKey,\n\tvalue: string | undefined,\n): void {\n\tswitch (key) {\n\t\tcase 'gk-last-accessed':\n\t\t\tif (value != null) {\n\t\t\t\tmetadata.lastAccessedAt = value;\n\t\t\t} else {\n\t\t\t\tdelete metadata.lastAccessedAt;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'gk-last-modified':\n\t\t\tif (value != null) {\n\t\t\t\tmetadata.lastModifiedAt = value;\n\t\t\t} else {\n\t\t\t\tdelete metadata.lastModifiedAt;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'gk-agent-last-activity':\n\t\t\tif (value != null) {\n\t\t\t\tmetadata.agentLastActivityAt = value;\n\t\t\t} else {\n\t\t\t\tdelete metadata.agentLastActivityAt;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'gk-disposition':\n\t\t\tif (value === 'starred' || value === 'archived') {\n\t\t\t\tmetadata.disposition = value;\n\t\t\t} else {\n\t\t\t\tdelete metadata.disposition;\n\t\t\t}\n\t\t\tbreak;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;AAiBA,MAAM,oBAAoB;AAE1B,SAAgB,uBAAuB,KAAqB;CAC3D,OAAO,IAAI,gBAAgB,GAAG,EAAE;AACjC;AAEA,SAAgB,uBAAuB,KAAqE;CAC3G,IAAI,IAAI,QAAQ;EACf,MAAM,QAAQ,wBAAwB,IAAI,IAAI;EAC9C,IAAI,UAAU,IAAI,OAAO,CAAC,IAAI,MAAM,KAAA,CAAS;EAE7C,OAAO,CAAC,IAAI,KAAK,UAAU,QAAQ,CAAC,GAAG,IAAI,KAAK,UAAU,GAAG,KAAK,CAAC;CACpE;CAEA,IAAI,IAAI,UAAU,QAAQ,OAAO,CAAC,IAAI,MAAM,IAAI,SAAS,MAAM;CAE/D,IAAI,IAAI,UAAU,QAAQ,MAAM;EAC/B,MAAM,QAAQ,wBAAwB,IAAI,SAAS,IAAI;EACvD,IAAI,UAAU,IAAI,OAAO,CAAC,IAAI,MAAM,KAAA,CAAS;EAE7C,OAAO,CAAC,IAAI,MAAM,IAAI,SAAS,KAAK,UAAU,GAAG,KAAK,CAAC;CACxD;CAEA,OAAO,CAAC,IAAI,MAAM,KAAA,CAAS;AAC5B;AAEA,SAAgB,+BAA+B,KAA6C;CAC3F,IAAI,IAAI,YAAY,MAAM,OAAO,KAAA;CAEjC,MAAM,EAAE,MAAM,WAAW,IAAI;CAC7B,IAAI,UAAU,KAAK,WAAW,GAAG,OAAO,EAAE,GAAG,OAAO,KAAK,UAAU,OAAO,SAAS,CAAC;CAEpF,OAAO,KAAK,UAAU,wBAAwB,IAAI,IAAI,CAAC;AACxD;;AAGA,SAAgB,sBACf,MACA,aAC+C;CAC/C,IAAI,KAAK,WAAW,UAAU,GAC7B,OAAO,KAAK,UAAU,CAAC;CAGxB,IAAI;CACJ,KAAK,MAAM,UAAU,aACpB,IACC,KAAK,SAAS,OAAO,SAAS,KAC9B,KAAK,WAAW,OAAO,MAAM,MAAM,MACnC,KAAK,WAAW,MAAM,MACrB,SAAS,QAAQ,OAAO,SAAS,MAAM,SAExC,QAAQ;CAIV,OAAO,SAAS,OAAO,CAAC,OAAO,KAAK,UAAU,MAAM,SAAS,CAAC,CAAC,IAAI,KAAA;AACpE;AAEA,SAAgB,eAAe,MAAuB;CAGrD,OAAO,KAAK,KAAK;CACjB,OAAO,KAAK,SAAS,kBAAkB,KAAK,IAAI,IAAI;AACrD;AAEA,SAAgB,kBAAkB,QAAgE;CACjG,OAAO,QAAQ,YAAY;AAC5B;AAEA,MAAM,2BAA2B;AACjC,MAAM,4BAA4B;AAClC,MAAM,kBAAkB;AAExB,SAAgB,eAAe,SAA0B;CACxD,OAAO,0BAA0B,KAAK,OAAO;AAC9C;AAEA,SAAgB,aAAa,SAA0B;CACtD,OAAO,gBAAgB,KAAK,OAAO;AACpC;AAEA,SAAgB,aAAa,SAAoD;CAChF,MAAM,SAAS,eAAe,OAAO;CAErC,IAAI;CACJ,IAAI,QAEH,OAAO,QAAQ,QAAQ,2BAA2B,EAAE;MAGpD,OAAO,QAAQ,QAAQ,0BAA0B,EAAE;CAGpD,OAAO;EAAQ;EAAc;CAAO;AACrC;AAEA,eAAsB,yBACrB,kBACA,UACiC;CACjC,IAAI;CACJ,IAAI,iBAAiB,WAAW,UAAU,GAAG;EAC5C,4BAA4B;EAC5B,mBAAmB,iBAAiB,UAAU,CAAC;CAChD,OACC,4BAA4B,WAAW;CAGxC,SAAS,QAAQ,QAA4B;EAC5C,OACC,CAAC,OAAO,UACR,OAAO,UAAU,QAAQ,SACxB,OAAO,SAAS,SAAS,oBAAoB,OAAO,SAAS,SAAS;CAEzE;CAEA,MAAM,SAAS,SAAS,OAAO;CAC/B,IAAI,OAAO,iBAAiB,QAChB;aAAA,MAAM,UAAU,QAC1B,IAAI,QAAQ,MAAM,GAAG,OAAO;CAAA,OAG7B,KAAK,MAAM,UAAU,QACpB,IAAI,QAAQ,MAAM,GAAG,OAAO;AAK/B;AAEA,eAAsB,4BAA4B,UAA2D;CAC5G,MAAM,iCAAiB,IAAI,IAAY;CAEvC,WAAW,MAAM,UAAU,SAAS,OAAO,GAC1C,IAAI,CAAC,OAAO,UAAU,OAAO,UAAU,QAAQ,MAC9C,eAAe,IAAI,OAAO,SAAS,IAAI;CAIzC,OAAO;AACR;AAEA,MAAM,qBAAqB;;AAG3B,SAAgB,cAAc,UAAkB,UAAkB,QAAkD;CACnH,IAAI,CAAC,UAAU,OAAO,KAAA;CAEtB,MAAM,EAAE,SAAS,aAAa,QAAQ;CACtC,MAAM,aAAa,UAAU,WAAW,MAAM,EAAU,OAAO,IAAI,KAAA;CAEnE,MAAM,QAAQ,mBAAmB,KAAK,QAAQ;CAC9C,IAAI,SAAS,MACZ,OAAO;EAAQ;EAAM,SAAS;EAAO,OAAO;GAAE,OAAO;GAAG,QAAQ;EAAE;EAAG,GAAG;CAAW;CAGpF,MAAM,QAAQ,MAAM,MAAM,OAAO,IAAI,OAAO,MAAM,EAAE;CACpD,MAAM,SAAS,MAAM,MAAM,OAAO,IAAI,OAAO,MAAM,EAAE;CAErD,OAAO;EACA;EACN,SAAS,MAAM,MAAM;EACrB,OAAO;GAAE,OAAO,MAAM,KAAK,IAAI,IAAI;GAAO,QAAQ,MAAM,MAAM,IAAI,IAAI;EAAO;EAC7E,GAAG;CACJ;AACD;AAEA,MAAM,iCACL;;AAGD,SAAgB,+BACf,KACiE;CACjE,MAAM,QAAQ,+BAA+B,KAAK,GAAG;CACrD,IAAI,SAAS,MAAM,OAAO,KAAA;CAE1B,OAAO;EAAE,QAAQ,MAAM;EAAI,KAAK,MAAM;CAAgC;AACvE;;AAGA,SAAgB,uBACf,UACA,KACA,OACO;CACP,QAAQ,KAAR;EACC,KAAK;GACJ,IAAI,SAAS,MACZ,SAAS,iBAAiB;QAE1B,OAAO,SAAS;GAEjB;EACD,KAAK;GACJ,IAAI,SAAS,MACZ,SAAS,iBAAiB;QAE1B,OAAO,SAAS;GAEjB;EACD,KAAK;GACJ,IAAI,SAAS,MACZ,SAAS,sBAAsB;QAE/B,OAAO,SAAS;GAEjB;EACD,KAAK,kBACJ,IAAI,UAAU,aAAa,UAAU,YACpC,SAAS,cAAc;OAEvB,OAAO,SAAS;CAGnB;AACD"}
@@ -9,6 +9,7 @@ interface GitBranchReferenceOptions {
9
9
  upstream?: {
10
10
  name: string;
11
11
  missing: boolean;
12
+ remote?: string;
12
13
  };
13
14
  worktree?: {
14
15
  path: string;
@@ -1 +1 @@
1
- {"version":3,"file":"reference.utils.js","names":[],"sources":["../../../../git/src/utils/reference.utils.ts"],"sourcesContent":["import * as l10n from '@vscode/l10n';\nimport { getBranchNameWithoutRemote, getRemoteNameFromBranchName } from '@gitlens/utils/gitRefs.js';\nimport type {\n\tGitBranchReference,\n\tGitReference,\n\tGitRevisionReference,\n\tGitStashReference,\n\tGitTagReference,\n} from '../models/reference.js';\nimport { isRevisionRange, isShaWithParentSuffix, shortenRevision } from './revision.utils.js';\n\ninterface GitBranchReferenceOptions {\n\trefType: 'branch';\n\tid?: string;\n\tname: string;\n\tremote: boolean;\n\tsha?: string;\n\tupstream?: { name: string; missing: boolean };\n\tworktree?: { path: string; isDefault: boolean } | boolean;\n}\n\ninterface GitCommitReferenceOptions {\n\trefType: 'revision';\n\tname?: string;\n\tmessage?: string;\n}\n\ninterface GitStashReferenceOptions {\n\trefType: 'stash';\n\tname: string;\n\tnumber: string | undefined;\n\tmessage?: string;\n\tstashOnRef?: string;\n}\n\ninterface GitTagReferenceOptions {\n\trefType: 'tag';\n\tid?: string;\n\tname: string;\n\tsha?: string;\n}\n\nexport function createReference(ref: string, repoPath: string, options: GitBranchReferenceOptions): GitBranchReference;\nexport function createReference(ref: string, repoPath: string, options: GitStashReferenceOptions): GitStashReference;\nexport function createReference(ref: string, repoPath: string, options: GitTagReferenceOptions): GitTagReference;\nexport function createReference(\n\tref: string,\n\trepoPath: string,\n\toptions?: GitCommitReferenceOptions,\n): GitRevisionReference;\nexport function createReference(\n\tref: string,\n\trepoPath: string,\n\toptions:\n\t\t| GitBranchReferenceOptions\n\t\t| GitStashReferenceOptions\n\t\t| GitTagReferenceOptions\n\t\t| GitCommitReferenceOptions = { refType: 'revision' },\n): GitReference {\n\tswitch (options.refType) {\n\t\tcase 'branch':\n\t\t\treturn {\n\t\t\t\trefType: 'branch',\n\t\t\t\trepoPath: repoPath,\n\t\t\t\tref: ref,\n\t\t\t\tname: options.name,\n\t\t\t\tid: options.id,\n\t\t\t\tremote: options.remote,\n\t\t\t\tsha: options.sha,\n\t\t\t\tupstream: options.upstream,\n\t\t\t\tworktree: options.worktree,\n\t\t\t};\n\t\tcase 'stash':\n\t\t\treturn {\n\t\t\t\trefType: 'stash',\n\t\t\t\trepoPath: repoPath,\n\t\t\t\tref: ref,\n\t\t\t\tsha: ref,\n\t\t\t\tname: options.name,\n\t\t\t\tstashNumber: options.number,\n\t\t\t\tmessage: options.message,\n\t\t\t\tstashOnRef: options.stashOnRef,\n\t\t\t};\n\t\tcase 'tag':\n\t\t\treturn {\n\t\t\t\trefType: 'tag',\n\t\t\t\trepoPath: repoPath,\n\t\t\t\tref: ref,\n\t\t\t\tname: options.name,\n\t\t\t\tid: options.id,\n\t\t\t\tsha: options.sha,\n\t\t\t};\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\trefType: 'revision',\n\t\t\t\trepoPath: repoPath,\n\t\t\t\tref: ref,\n\t\t\t\tsha: ref,\n\t\t\t\tname:\n\t\t\t\t\toptions.name ??\n\t\t\t\t\tshortenRevision(ref, {\n\t\t\t\t\t\tstrings: {\n\t\t\t\t\t\t\tuncommitted: l10n.t('Working Tree'),\n\t\t\t\t\t\t\tuncommittedStaged: l10n.t('Index'),\n\t\t\t\t\t\t\tworking: l10n.t('Working Tree'),\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\tmessage: options.message,\n\t\t\t};\n\t}\n}\n\nexport function getReferenceNameWithoutRemote(ref: GitReference): string {\n\tif (ref.refType === 'branch') {\n\t\treturn ref.remote ? getBranchNameWithoutRemote(ref.name) : ref.name;\n\t}\n\treturn ref.name;\n}\n\nexport function getReferenceTypeLabel(ref: GitReference | undefined): string {\n\tswitch (ref?.refType) {\n\t\tcase 'branch':\n\t\t\treturn l10n.t('Branch');\n\t\tcase 'stash':\n\t\t\treturn l10n.t('Stash');\n\t\tcase 'tag':\n\t\t\treturn l10n.t('Tag');\n\t\tdefault:\n\t\t\treturn l10n.t('Commit');\n\t}\n}\n\nexport function isBranchReference(ref: GitReference | undefined): ref is GitBranchReference {\n\treturn ref?.refType === 'branch';\n}\n\nexport function isGitReference(ref: unknown): ref is GitReference {\n\tif (ref == null || typeof ref !== 'object') return false;\n\n\tconst r = ref as GitReference;\n\treturn (\n\t\ttypeof r.refType === 'string' &&\n\t\ttypeof r.repoPath === 'string' &&\n\t\ttypeof r.ref === 'string' &&\n\t\ttypeof r.name === 'string'\n\t);\n}\n\nexport function isRevisionReference(ref: GitReference | undefined): ref is GitRevisionReference {\n\treturn ref?.refType === 'revision';\n}\n\nexport function isRevisionRangeReference(ref: GitReference | undefined): ref is GitRevisionReference {\n\treturn ref?.refType === 'revision' && isRevisionRange(ref.ref);\n}\n\nexport function isStashReference(ref: GitReference | undefined): ref is GitStashReference {\n\treturn ref?.refType === 'stash' || (ref?.refType === 'revision' && Boolean('stashName' in ref && ref.stashName));\n}\n\nexport function isTagReference(ref: GitReference | undefined): ref is GitTagReference {\n\treturn ref?.refType === 'tag';\n}\n\nexport function getReferenceLabel(\n\trefs: GitReference | GitReference[] | undefined,\n\toptions?: { capitalize?: boolean; expand?: boolean; icon?: boolean; label?: boolean; quoted?: boolean } | false,\n): string {\n\tif (refs == null) return '';\n\n\toptions =\n\t\toptions === false\n\t\t\t? {}\n\t\t\t: { expand: true, icon: true, label: options?.label ?? options?.expand ?? true, ...options };\n\n\tlet result;\n\tif (!Array.isArray(refs) || refs.length === 1) {\n\t\tconst ref = Array.isArray(refs) ? refs[0] : refs;\n\t\tlet refName = options?.quoted ? `'${ref.name}'` : ref.name;\n\t\tswitch (ref.refType) {\n\t\t\tcase 'branch': {\n\t\t\t\tif (ref.remote) {\n\t\t\t\t\trefName = `${getRemoteNameFromBranchName(refName)}: ${getBranchNameWithoutRemote(refName)}`;\n\t\t\t\t\trefName = options?.quoted ? `'${refName}'` : refName;\n\t\t\t\t}\n\n\t\t\t\tif (options.label) {\n\t\t\t\t\tif (options.icon) {\n\t\t\t\t\t\tif (options.capitalize && options.expand) {\n\t\t\t\t\t\t\tresult = ref.remote\n\t\t\t\t\t\t\t\t? l10n.t('Remote Branch $(git-branch)\\u00a0{0}', refName)\n\t\t\t\t\t\t\t\t: l10n.t('Branch $(git-branch)\\u00a0{0}', refName);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresult = ref.remote\n\t\t\t\t\t\t\t\t? l10n.t('remote branch $(git-branch)\\u00a0{0}', refName)\n\t\t\t\t\t\t\t\t: l10n.t('branch $(git-branch)\\u00a0{0}', refName);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (options.capitalize && options.expand) {\n\t\t\t\t\t\tresult = ref.remote ? l10n.t('Remote Branch {0}', refName) : l10n.t('Branch {0}', refName);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = ref.remote ? l10n.t('remote branch {0}', refName) : l10n.t('branch {0}', refName);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tresult = options.icon ? `$(git-branch)\\u00a0${refName}` : refName;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'tag':\n\t\t\t\tif (options.label) {\n\t\t\t\t\tif (options.icon) {\n\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t? l10n.t('Tag $(tag)\\u00a0{0}', refName)\n\t\t\t\t\t\t\t\t: l10n.t('tag $(tag)\\u00a0{0}', refName);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t? l10n.t('Tag {0}', refName)\n\t\t\t\t\t\t\t\t: l10n.t('tag {0}', refName);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tresult = options.icon ? `$(tag)\\u00a0${refName}` : refName;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tif (isStashReference(ref)) {\n\t\t\t\t\tlet message;\n\t\t\t\t\tif (options.expand && ref.message) {\n\t\t\t\t\t\tmessage = `${ref.stashNumber != null ? `#${ref.stashNumber}: ` : ''}${\n\t\t\t\t\t\t\tref.message.length > 20 ? `${ref.message.substring(0, 20).trimEnd()}\\u2026` : ref.message\n\t\t\t\t\t\t}`;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst stashName = message ?? (ref.stashNumber ? `#${ref.stashNumber}` : ref.name);\n\t\t\t\t\tif (options.label) {\n\t\t\t\t\t\tif (options.icon) {\n\t\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t\t? l10n.t('Stash $(archive)\\u00a0{0}', message ?? ref.name)\n\t\t\t\t\t\t\t\t\t: l10n.t('stash $(archive)\\u00a0{0}', message ?? ref.name);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t\t? l10n.t('Stash {0}', stashName)\n\t\t\t\t\t\t\t\t\t: l10n.t('stash {0}', stashName);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = options.icon ? `$(archive)\\u00a0${message ?? ref.name}` : stashName;\n\t\t\t\t\t}\n\t\t\t\t} else if (isRevisionRange(ref.ref)) {\n\t\t\t\t\tresult = refName;\n\t\t\t\t} else {\n\t\t\t\t\tlet message;\n\t\t\t\t\tif (options.expand && ref.message) {\n\t\t\t\t\t\tmessage =\n\t\t\t\t\t\t\tref.message.length > 20\n\t\t\t\t\t\t\t\t? ` (${ref.message.substring(0, 20).trimEnd()}\\u2026)`\n\t\t\t\t\t\t\t\t: ` (${ref.message})`;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet before = false;\n\t\t\t\t\tif (options.expand && options.label && isShaWithParentSuffix(ref.ref)) {\n\t\t\t\t\t\trefName = ref.name.endsWith('^') ? ref.name.substring(0, ref.name.length - 1) : ref.name;\n\t\t\t\t\t\tif (options?.quoted) {\n\t\t\t\t\t\t\trefName = `'${refName}'`;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbefore = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (options.label) {\n\t\t\t\t\t\tif (options.icon) {\n\t\t\t\t\t\t\tif (before) {\n\t\t\t\t\t\t\t\tresult = options.capitalize\n\t\t\t\t\t\t\t\t\t? l10n.t('Before commit $(git-commit)\\u00a0{0}{1}', refName, message ?? '')\n\t\t\t\t\t\t\t\t\t: l10n.t('before commit $(git-commit)\\u00a0{0}{1}', refName, message ?? '');\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t\t\t? l10n.t('Commit $(git-commit)\\u00a0{0}{1}', refName, message ?? '')\n\t\t\t\t\t\t\t\t\t\t: l10n.t('commit $(git-commit)\\u00a0{0}{1}', refName, message ?? '');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (before) {\n\t\t\t\t\t\t\tresult = options.capitalize\n\t\t\t\t\t\t\t\t? l10n.t('Before commit {0}{1}', refName, message ?? '')\n\t\t\t\t\t\t\t\t: l10n.t('before commit {0}{1}', refName, message ?? '');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t\t? l10n.t('Commit {0}{1}', refName, message ?? '')\n\t\t\t\t\t\t\t\t\t: l10n.t('commit {0}{1}', refName, message ?? '');\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = options.icon\n\t\t\t\t\t\t\t? `$(git-commit)\\u00a0${refName}${message ?? ''}`\n\t\t\t\t\t\t\t: `${refName}${message ?? ''}`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tconst expanded = options.expand ? ` (${refs.map(r => r.name).join(', ')})` : '';\n\tswitch (refs[0].refType) {\n\t\tcase 'branch':\n\t\t\treturn l10n.t('{0} branches{1}', refs.length, expanded);\n\t\tcase 'tag':\n\t\t\treturn l10n.t('{0} tags{1}', refs.length, expanded);\n\t\tdefault:\n\t\t\treturn isStashReference(refs[0])\n\t\t\t\t? l10n.t('{0} stashes{1}', refs.length, expanded)\n\t\t\t\t: l10n.t('{0} commits{1}', refs.length, expanded);\n\t}\n}\n\nexport function getReferenceTypeIcon(ref: GitReference | undefined, webview?: boolean): string {\n\tswitch (ref?.refType) {\n\t\tcase 'branch':\n\t\t\tif (ref.remote) return 'cloud';\n\t\t\tif (ref.worktree) return webview ? 'gl-worktree' : 'gitlens-worktree';\n\t\t\treturn 'git-branch';\n\t\tcase 'tag':\n\t\t\treturn 'tag';\n\t\tcase 'stash':\n\t\t\treturn 'archive';\n\t\tdefault:\n\t\t\treturn 'git-commit';\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"reference.utils.js","names":[],"sources":["../../../../git/src/utils/reference.utils.ts"],"sourcesContent":["import * as l10n from '@vscode/l10n';\nimport { getBranchNameWithoutRemote, getRemoteNameFromBranchName } from '@gitlens/utils/gitRefs.js';\nimport type {\n\tGitBranchReference,\n\tGitReference,\n\tGitRevisionReference,\n\tGitStashReference,\n\tGitTagReference,\n} from '../models/reference.js';\nimport { isRevisionRange, isShaWithParentSuffix, shortenRevision } from './revision.utils.js';\n\ninterface GitBranchReferenceOptions {\n\trefType: 'branch';\n\tid?: string;\n\tname: string;\n\tremote: boolean;\n\tsha?: string;\n\tupstream?: { name: string; missing: boolean; remote?: string };\n\tworktree?: { path: string; isDefault: boolean } | boolean;\n}\n\ninterface GitCommitReferenceOptions {\n\trefType: 'revision';\n\tname?: string;\n\tmessage?: string;\n}\n\ninterface GitStashReferenceOptions {\n\trefType: 'stash';\n\tname: string;\n\tnumber: string | undefined;\n\tmessage?: string;\n\tstashOnRef?: string;\n}\n\ninterface GitTagReferenceOptions {\n\trefType: 'tag';\n\tid?: string;\n\tname: string;\n\tsha?: string;\n}\n\nexport function createReference(ref: string, repoPath: string, options: GitBranchReferenceOptions): GitBranchReference;\nexport function createReference(ref: string, repoPath: string, options: GitStashReferenceOptions): GitStashReference;\nexport function createReference(ref: string, repoPath: string, options: GitTagReferenceOptions): GitTagReference;\nexport function createReference(\n\tref: string,\n\trepoPath: string,\n\toptions?: GitCommitReferenceOptions,\n): GitRevisionReference;\nexport function createReference(\n\tref: string,\n\trepoPath: string,\n\toptions:\n\t\t| GitBranchReferenceOptions\n\t\t| GitStashReferenceOptions\n\t\t| GitTagReferenceOptions\n\t\t| GitCommitReferenceOptions = { refType: 'revision' },\n): GitReference {\n\tswitch (options.refType) {\n\t\tcase 'branch':\n\t\t\treturn {\n\t\t\t\trefType: 'branch',\n\t\t\t\trepoPath: repoPath,\n\t\t\t\tref: ref,\n\t\t\t\tname: options.name,\n\t\t\t\tid: options.id,\n\t\t\t\tremote: options.remote,\n\t\t\t\tsha: options.sha,\n\t\t\t\tupstream: options.upstream,\n\t\t\t\tworktree: options.worktree,\n\t\t\t};\n\t\tcase 'stash':\n\t\t\treturn {\n\t\t\t\trefType: 'stash',\n\t\t\t\trepoPath: repoPath,\n\t\t\t\tref: ref,\n\t\t\t\tsha: ref,\n\t\t\t\tname: options.name,\n\t\t\t\tstashNumber: options.number,\n\t\t\t\tmessage: options.message,\n\t\t\t\tstashOnRef: options.stashOnRef,\n\t\t\t};\n\t\tcase 'tag':\n\t\t\treturn {\n\t\t\t\trefType: 'tag',\n\t\t\t\trepoPath: repoPath,\n\t\t\t\tref: ref,\n\t\t\t\tname: options.name,\n\t\t\t\tid: options.id,\n\t\t\t\tsha: options.sha,\n\t\t\t};\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\trefType: 'revision',\n\t\t\t\trepoPath: repoPath,\n\t\t\t\tref: ref,\n\t\t\t\tsha: ref,\n\t\t\t\tname:\n\t\t\t\t\toptions.name ??\n\t\t\t\t\tshortenRevision(ref, {\n\t\t\t\t\t\tstrings: {\n\t\t\t\t\t\t\tuncommitted: l10n.t('Working Tree'),\n\t\t\t\t\t\t\tuncommittedStaged: l10n.t('Index'),\n\t\t\t\t\t\t\tworking: l10n.t('Working Tree'),\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\tmessage: options.message,\n\t\t\t};\n\t}\n}\n\nexport function getReferenceNameWithoutRemote(ref: GitReference): string {\n\tif (ref.refType === 'branch') {\n\t\treturn ref.remote ? getBranchNameWithoutRemote(ref.name) : ref.name;\n\t}\n\treturn ref.name;\n}\n\nexport function getReferenceTypeLabel(ref: GitReference | undefined): string {\n\tswitch (ref?.refType) {\n\t\tcase 'branch':\n\t\t\treturn l10n.t('Branch');\n\t\tcase 'stash':\n\t\t\treturn l10n.t('Stash');\n\t\tcase 'tag':\n\t\t\treturn l10n.t('Tag');\n\t\tdefault:\n\t\t\treturn l10n.t('Commit');\n\t}\n}\n\nexport function isBranchReference(ref: GitReference | undefined): ref is GitBranchReference {\n\treturn ref?.refType === 'branch';\n}\n\nexport function isGitReference(ref: unknown): ref is GitReference {\n\tif (ref == null || typeof ref !== 'object') return false;\n\n\tconst r = ref as GitReference;\n\treturn (\n\t\ttypeof r.refType === 'string' &&\n\t\ttypeof r.repoPath === 'string' &&\n\t\ttypeof r.ref === 'string' &&\n\t\ttypeof r.name === 'string'\n\t);\n}\n\nexport function isRevisionReference(ref: GitReference | undefined): ref is GitRevisionReference {\n\treturn ref?.refType === 'revision';\n}\n\nexport function isRevisionRangeReference(ref: GitReference | undefined): ref is GitRevisionReference {\n\treturn ref?.refType === 'revision' && isRevisionRange(ref.ref);\n}\n\nexport function isStashReference(ref: GitReference | undefined): ref is GitStashReference {\n\treturn ref?.refType === 'stash' || (ref?.refType === 'revision' && Boolean('stashName' in ref && ref.stashName));\n}\n\nexport function isTagReference(ref: GitReference | undefined): ref is GitTagReference {\n\treturn ref?.refType === 'tag';\n}\n\nexport function getReferenceLabel(\n\trefs: GitReference | GitReference[] | undefined,\n\toptions?: { capitalize?: boolean; expand?: boolean; icon?: boolean; label?: boolean; quoted?: boolean } | false,\n): string {\n\tif (refs == null) return '';\n\n\toptions =\n\t\toptions === false\n\t\t\t? {}\n\t\t\t: { expand: true, icon: true, label: options?.label ?? options?.expand ?? true, ...options };\n\n\tlet result;\n\tif (!Array.isArray(refs) || refs.length === 1) {\n\t\tconst ref = Array.isArray(refs) ? refs[0] : refs;\n\t\tlet refName = options?.quoted ? `'${ref.name}'` : ref.name;\n\t\tswitch (ref.refType) {\n\t\t\tcase 'branch': {\n\t\t\t\tif (ref.remote) {\n\t\t\t\t\trefName = `${getRemoteNameFromBranchName(refName)}: ${getBranchNameWithoutRemote(refName)}`;\n\t\t\t\t\trefName = options?.quoted ? `'${refName}'` : refName;\n\t\t\t\t}\n\n\t\t\t\tif (options.label) {\n\t\t\t\t\tif (options.icon) {\n\t\t\t\t\t\tif (options.capitalize && options.expand) {\n\t\t\t\t\t\t\tresult = ref.remote\n\t\t\t\t\t\t\t\t? l10n.t('Remote Branch $(git-branch)\\u00a0{0}', refName)\n\t\t\t\t\t\t\t\t: l10n.t('Branch $(git-branch)\\u00a0{0}', refName);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresult = ref.remote\n\t\t\t\t\t\t\t\t? l10n.t('remote branch $(git-branch)\\u00a0{0}', refName)\n\t\t\t\t\t\t\t\t: l10n.t('branch $(git-branch)\\u00a0{0}', refName);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (options.capitalize && options.expand) {\n\t\t\t\t\t\tresult = ref.remote ? l10n.t('Remote Branch {0}', refName) : l10n.t('Branch {0}', refName);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = ref.remote ? l10n.t('remote branch {0}', refName) : l10n.t('branch {0}', refName);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tresult = options.icon ? `$(git-branch)\\u00a0${refName}` : refName;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'tag':\n\t\t\t\tif (options.label) {\n\t\t\t\t\tif (options.icon) {\n\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t? l10n.t('Tag $(tag)\\u00a0{0}', refName)\n\t\t\t\t\t\t\t\t: l10n.t('tag $(tag)\\u00a0{0}', refName);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t? l10n.t('Tag {0}', refName)\n\t\t\t\t\t\t\t\t: l10n.t('tag {0}', refName);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tresult = options.icon ? `$(tag)\\u00a0${refName}` : refName;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tif (isStashReference(ref)) {\n\t\t\t\t\tlet message;\n\t\t\t\t\tif (options.expand && ref.message) {\n\t\t\t\t\t\tmessage = `${ref.stashNumber != null ? `#${ref.stashNumber}: ` : ''}${\n\t\t\t\t\t\t\tref.message.length > 20 ? `${ref.message.substring(0, 20).trimEnd()}\\u2026` : ref.message\n\t\t\t\t\t\t}`;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst stashName = message ?? (ref.stashNumber ? `#${ref.stashNumber}` : ref.name);\n\t\t\t\t\tif (options.label) {\n\t\t\t\t\t\tif (options.icon) {\n\t\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t\t? l10n.t('Stash $(archive)\\u00a0{0}', message ?? ref.name)\n\t\t\t\t\t\t\t\t\t: l10n.t('stash $(archive)\\u00a0{0}', message ?? ref.name);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t\t? l10n.t('Stash {0}', stashName)\n\t\t\t\t\t\t\t\t\t: l10n.t('stash {0}', stashName);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = options.icon ? `$(archive)\\u00a0${message ?? ref.name}` : stashName;\n\t\t\t\t\t}\n\t\t\t\t} else if (isRevisionRange(ref.ref)) {\n\t\t\t\t\tresult = refName;\n\t\t\t\t} else {\n\t\t\t\t\tlet message;\n\t\t\t\t\tif (options.expand && ref.message) {\n\t\t\t\t\t\tmessage =\n\t\t\t\t\t\t\tref.message.length > 20\n\t\t\t\t\t\t\t\t? ` (${ref.message.substring(0, 20).trimEnd()}\\u2026)`\n\t\t\t\t\t\t\t\t: ` (${ref.message})`;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet before = false;\n\t\t\t\t\tif (options.expand && options.label && isShaWithParentSuffix(ref.ref)) {\n\t\t\t\t\t\trefName = ref.name.endsWith('^') ? ref.name.substring(0, ref.name.length - 1) : ref.name;\n\t\t\t\t\t\tif (options?.quoted) {\n\t\t\t\t\t\t\trefName = `'${refName}'`;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbefore = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (options.label) {\n\t\t\t\t\t\tif (options.icon) {\n\t\t\t\t\t\t\tif (before) {\n\t\t\t\t\t\t\t\tresult = options.capitalize\n\t\t\t\t\t\t\t\t\t? l10n.t('Before commit $(git-commit)\\u00a0{0}{1}', refName, message ?? '')\n\t\t\t\t\t\t\t\t\t: l10n.t('before commit $(git-commit)\\u00a0{0}{1}', refName, message ?? '');\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t\t\t? l10n.t('Commit $(git-commit)\\u00a0{0}{1}', refName, message ?? '')\n\t\t\t\t\t\t\t\t\t\t: l10n.t('commit $(git-commit)\\u00a0{0}{1}', refName, message ?? '');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (before) {\n\t\t\t\t\t\t\tresult = options.capitalize\n\t\t\t\t\t\t\t\t? l10n.t('Before commit {0}{1}', refName, message ?? '')\n\t\t\t\t\t\t\t\t: l10n.t('before commit {0}{1}', refName, message ?? '');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresult =\n\t\t\t\t\t\t\t\toptions.capitalize && options.expand\n\t\t\t\t\t\t\t\t\t? l10n.t('Commit {0}{1}', refName, message ?? '')\n\t\t\t\t\t\t\t\t\t: l10n.t('commit {0}{1}', refName, message ?? '');\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = options.icon\n\t\t\t\t\t\t\t? `$(git-commit)\\u00a0${refName}${message ?? ''}`\n\t\t\t\t\t\t\t: `${refName}${message ?? ''}`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tconst expanded = options.expand ? ` (${refs.map(r => r.name).join(', ')})` : '';\n\tswitch (refs[0].refType) {\n\t\tcase 'branch':\n\t\t\treturn l10n.t('{0} branches{1}', refs.length, expanded);\n\t\tcase 'tag':\n\t\t\treturn l10n.t('{0} tags{1}', refs.length, expanded);\n\t\tdefault:\n\t\t\treturn isStashReference(refs[0])\n\t\t\t\t? l10n.t('{0} stashes{1}', refs.length, expanded)\n\t\t\t\t: l10n.t('{0} commits{1}', refs.length, expanded);\n\t}\n}\n\nexport function getReferenceTypeIcon(ref: GitReference | undefined, webview?: boolean): string {\n\tswitch (ref?.refType) {\n\t\tcase 'branch':\n\t\t\tif (ref.remote) return 'cloud';\n\t\t\tif (ref.worktree) return webview ? 'gl-worktree' : 'gitlens-worktree';\n\t\t\treturn 'git-branch';\n\t\tcase 'tag':\n\t\t\treturn 'tag';\n\t\tcase 'stash':\n\t\t\treturn 'archive';\n\t\tdefault:\n\t\t\treturn 'git-commit';\n\t}\n}\n"],"mappings":"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"}