@gitkraken/core-gitlens 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -1
- package/dist/git/cache.d.ts +21 -5
- package/dist/git/cache.d.ts.map +1 -1
- package/dist/git/cache.js +102 -6
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +11 -2
- package/dist/git/context.d.ts.map +1 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/models/branch.d.ts +1 -0
- package/dist/git/models/branch.d.ts.map +1 -1
- package/dist/git/models/branch.js.map +1 -1
- package/dist/git/models/commit.d.ts +1 -9
- package/dist/git/models/commit.d.ts.map +1 -1
- package/dist/git/models/commit.js +4 -9
- package/dist/git/models/commit.js.map +1 -1
- package/dist/git/models/graph.d.ts +2 -4
- package/dist/git/models/graph.d.ts.map +1 -1
- package/dist/git/models/repository.d.ts +12 -3
- package/dist/git/models/repository.d.ts.map +1 -1
- package/dist/git/models/repository.js +25 -4
- package/dist/git/models/repository.js.map +1 -1
- package/dist/git/models/worktree.d.ts +1 -1
- package/dist/git/models/worktree.d.ts.map +1 -1
- package/dist/git/models/worktree.js +2 -2
- package/dist/git/models/worktree.js.map +1 -1
- package/dist/git/parsers/diffParser.d.ts +0 -1
- package/dist/git/parsers/diffParser.d.ts.map +1 -1
- package/dist/git/parsers/diffParser.js +22 -61
- package/dist/git/parsers/diffParser.js.map +1 -1
- package/dist/git/providers/branches.d.ts +3 -0
- package/dist/git/providers/branches.d.ts.map +1 -1
- package/dist/git/providers/commits.d.ts +6 -0
- package/dist/git/providers/commits.d.ts.map +1 -1
- package/dist/git/providers/config.d.ts +2 -0
- package/dist/git/providers/config.d.ts.map +1 -1
- package/dist/git/providers/diff.d.ts +2 -0
- package/dist/git/providers/diff.d.ts.map +1 -1
- package/dist/git/providers/operations.d.ts +6 -0
- package/dist/git/providers/operations.d.ts.map +1 -1
- package/dist/git/providers/revision.d.ts +1 -1
- package/dist/git/providers/revision.d.ts.map +1 -1
- package/dist/git/providers/staging.d.ts +2 -0
- package/dist/git/providers/staging.d.ts.map +1 -1
- package/dist/git/utils/sorting.d.ts +6 -0
- package/dist/git/utils/sorting.d.ts.map +1 -1
- package/dist/git/utils/sorting.js +19 -0
- package/dist/git/utils/sorting.js.map +1 -1
- package/dist/git-cli/cliGitProvider.js +1 -1
- package/dist/git-cli/cliGitProvider.js.map +1 -1
- package/dist/git-cli/exec/git.d.ts +29 -4
- package/dist/git-cli/exec/git.d.ts.map +1 -1
- package/dist/git-cli/exec/git.js +70 -9
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/exec/gitQueue.d.ts +12 -4
- package/dist/git-cli/exec/gitQueue.d.ts.map +1 -1
- package/dist/git-cli/exec/gitQueue.js +49 -12
- package/dist/git-cli/exec/gitQueue.js.map +1 -1
- package/dist/git-cli/parsers/logParser.d.ts +1 -0
- package/dist/git-cli/parsers/logParser.d.ts.map +1 -1
- package/dist/git-cli/parsers/logParser.js +4 -0
- package/dist/git-cli/parsers/logParser.js.map +1 -1
- package/dist/git-cli/providers/blame.js +1 -1
- package/dist/git-cli/providers/blame.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +2 -0
- package/dist/git-cli/providers/branches.d.ts.map +1 -1
- package/dist/git-cli/providers/branches.js +176 -123
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.d.ts +4 -0
- package/dist/git-cli/providers/commits.d.ts.map +1 -1
- package/dist/git-cli/providers/commits.js +58 -17
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts.map +1 -1
- package/dist/git-cli/providers/config.js +9 -9
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/contributors.d.ts.map +1 -1
- package/dist/git-cli/providers/contributors.js +7 -4
- package/dist/git-cli/providers/contributors.js.map +1 -1
- package/dist/git-cli/providers/diff.d.ts +2 -0
- package/dist/git-cli/providers/diff.d.ts.map +1 -1
- package/dist/git-cli/providers/diff.js +89 -19
- package/dist/git-cli/providers/diff.js.map +1 -1
- package/dist/git-cli/providers/graph.d.ts.map +1 -1
- package/dist/git-cli/providers/graph.js +43 -27
- package/dist/git-cli/providers/graph.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +17 -0
- package/dist/git-cli/providers/operations.d.ts.map +1 -1
- package/dist/git-cli/providers/operations.js +47 -14
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/patch.d.ts.map +1 -1
- package/dist/git-cli/providers/patch.js +15 -30
- package/dist/git-cli/providers/patch.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.js +6 -6
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.d.ts.map +1 -1
- package/dist/git-cli/providers/refs.js +26 -7
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/remotes.js +4 -4
- package/dist/git-cli/providers/remotes.js.map +1 -1
- package/dist/git-cli/providers/revision.d.ts +1 -1
- package/dist/git-cli/providers/revision.d.ts.map +1 -1
- package/dist/git-cli/providers/revision.js +15 -11
- package/dist/git-cli/providers/revision.js.map +1 -1
- package/dist/git-cli/providers/staging.d.ts +2 -0
- package/dist/git-cli/providers/staging.d.ts.map +1 -1
- package/dist/git-cli/providers/staging.js +20 -8
- package/dist/git-cli/providers/staging.js.map +1 -1
- package/dist/git-cli/providers/stash.d.ts +0 -8
- package/dist/git-cli/providers/stash.d.ts.map +1 -1
- package/dist/git-cli/providers/stash.js +63 -119
- package/dist/git-cli/providers/stash.js.map +1 -1
- package/dist/git-cli/providers/status.js +6 -6
- package/dist/git-cli/providers/status.js.map +1 -1
- package/dist/git-cli/providers/tags.js +4 -4
- package/dist/git-cli/providers/tags.js.map +1 -1
- package/dist/git-cli/providers/worktrees.js +3 -3
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/plus/ai/constants.d.ts +2 -1
- package/dist/plus/ai/constants.d.ts.map +1 -1
- package/dist/plus/ai/constants.js +7 -0
- package/dist/plus/ai/constants.js.map +1 -1
- package/dist/plus/ai/models/model.d.ts +1 -1
- package/dist/plus/ai/models/model.d.ts.map +1 -1
- package/dist/plus/ai/models/model.js.map +1 -1
- package/dist/plus/ai/models/promptTemplates.d.ts +19 -2
- package/dist/plus/ai/models/promptTemplates.d.ts.map +1 -1
- package/dist/plus/ai/models/results.d.ts +28 -0
- package/dist/plus/ai/models/results.d.ts.map +1 -1
- package/dist/plus/ai/prompts.d.ts +3 -0
- package/dist/plus/ai/prompts.d.ts.map +1 -1
- package/dist/plus/ai/prompts.js +126 -0
- package/dist/plus/ai/prompts.js.map +1 -1
- package/dist/plus/ai/utils/ai.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/ai.utils.js +2 -0
- package/dist/plus/ai/utils/ai.utils.js.map +1 -1
- package/dist/plus/ai/utils/results.utils.d.ts +3 -0
- package/dist/plus/ai/utils/results.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/results.utils.js +75 -0
- package/dist/plus/ai/utils/results.utils.js.map +1 -1
- package/dist/plus/ai/utils/truncation.utils.d.ts +1 -1
- package/dist/plus/ai/utils/truncation.utils.d.ts.map +1 -1
- package/dist/plus/ai/utils/truncation.utils.js.map +1 -1
- package/dist/plus/git-github/providers/github/branches.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/branches.js +16 -1
- package/dist/plus/git-github/providers/github/branches.js.map +1 -1
- package/dist/plus/git-github/providers/github/diff.d.ts +2 -0
- package/dist/plus/git-github/providers/github/diff.d.ts.map +1 -1
- package/dist/plus/git-github/providers/github/diff.js.map +1 -1
- package/dist/utils/decorators/log.js +1 -1
- package/dist/utils/decorators/log.js.map +1 -1
- package/dist/utils/decorators/sequentialize.d.ts.map +1 -1
- package/dist/utils/decorators/sequentialize.js +4 -2
- package/dist/utils/decorators/sequentialize.js.map +1 -1
- package/dist/utils/env/node/base64.js.map +1 -1
- package/dist/utils/env/node/exec.js.map +1 -1
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +4 -10
- package/dist/utils/formatter.js.map +1 -1
- package/dist/utils/iterable.js.map +1 -1
- package/dist/utils/lruMap.d.ts +40 -0
- package/dist/utils/lruMap.d.ts.map +1 -0
- package/dist/utils/lruMap.js +81 -0
- package/dist/utils/lruMap.js.map +1 -0
- package/dist/utils/version.d.ts +14 -0
- package/dist/utils/version.d.ts.map +1 -1
- package/dist/utils/version.js +48 -0
- package/dist/utils/version.js.map +1 -1
- package/package.json +1 -1
- package/src/git/cache.ts +179 -13
- package/src/git/context.ts +11 -2
- package/src/git/models/branch.ts +1 -0
- package/src/git/models/commit.ts +1 -17
- package/src/git/models/graph.ts +2 -4
- package/src/git/models/repository.ts +26 -6
- package/src/git/models/worktree.ts +2 -2
- package/src/git/parsers/diffParser.ts +7 -44
- package/src/git/providers/branches.ts +3 -0
- package/src/git/providers/commits.ts +7 -0
- package/src/git/providers/config.ts +2 -0
- package/src/git/providers/diff.ts +8 -2
- package/src/git/providers/operations.ts +10 -3
- package/src/git/providers/revision.ts +5 -1
- package/src/git/providers/staging.ts +2 -0
- package/src/git/utils/sorting.ts +21 -0
- package/src/git-cli/cliGitProvider.ts +1 -1
- package/src/git-cli/exec/git.ts +70 -18
- package/src/git-cli/exec/gitQueue.ts +57 -13
- package/src/git-cli/parsers/logParser.ts +5 -1
- package/src/git-cli/providers/blame.ts +1 -1
- package/src/git-cli/providers/branches.ts +207 -133
- package/src/git-cli/providers/commits.ts +71 -18
- package/src/git-cli/providers/config.ts +9 -14
- package/src/git-cli/providers/contributors.ts +7 -12
- package/src/git-cli/providers/diff.ts +100 -19
- package/src/git-cli/providers/graph.ts +47 -27
- package/src/git-cli/providers/operations.ts +77 -18
- package/src/git-cli/providers/patch.ts +15 -37
- package/src/git-cli/providers/pausedOperations.ts +6 -6
- package/src/git-cli/providers/refs.ts +27 -8
- package/src/git-cli/providers/remotes.ts +4 -4
- package/src/git-cli/providers/revision.ts +20 -13
- package/src/git-cli/providers/staging.ts +18 -8
- package/src/git-cli/providers/stash.ts +67 -134
- package/src/git-cli/providers/status.ts +6 -6
- package/src/git-cli/providers/tags.ts +4 -4
- package/src/git-cli/providers/worktrees.ts +3 -3
- package/src/plus/ai/constants.ts +8 -0
- package/src/plus/ai/models/model.ts +1 -0
- package/src/plus/ai/models/promptTemplates.ts +29 -0
- package/src/plus/ai/models/results.ts +30 -0
- package/src/plus/ai/prompts.ts +129 -0
- package/src/plus/ai/utils/ai.utils.ts +2 -0
- package/src/plus/ai/utils/results.utils.ts +99 -0
- package/src/plus/ai/utils/truncation.utils.ts +3 -1
- package/src/plus/git-github/providers/github/branches.ts +17 -5
- package/src/plus/git-github/providers/github/diff.ts +8 -2
- package/src/utils/decorators/log.ts +1 -1
- package/src/utils/decorators/sequentialize.ts +8 -6
- package/src/utils/env/node/base64.ts +1 -1
- package/src/utils/env/node/exec.ts +2 -2
- package/src/utils/formatter.ts +4 -11
- package/src/utils/iterable.ts +1 -1
- package/src/utils/lruMap.ts +87 -0
- package/src/utils/version.ts +48 -0
|
@@ -12,6 +12,8 @@ export interface BranchContributionsOverview extends GitCommitStats<number> {
|
|
|
12
12
|
readonly branch: string;
|
|
13
13
|
readonly mergeTarget: string;
|
|
14
14
|
readonly mergeBase: string;
|
|
15
|
+
/** Committer date of the merge-base commit. Lets consumers (e.g. the graph minimap scope window) anchor on the same date semantics as the minimap aggregation without a separate commit fetch. */
|
|
16
|
+
readonly mergeBaseDate: Date | undefined;
|
|
15
17
|
|
|
16
18
|
readonly commits: number;
|
|
17
19
|
readonly latestCommitDate: Date | undefined;
|
|
@@ -98,6 +100,7 @@ export interface GitBranchesSubProvider {
|
|
|
98
100
|
getStoredUserMergeTargetBranchName?(repoPath: string, ref: string): Promise<string | undefined>;
|
|
99
101
|
onCurrentBranchAccessed?(repoPath: string): Promise<void>;
|
|
100
102
|
onCurrentBranchModified?(repoPath: string): Promise<void>;
|
|
103
|
+
onCurrentBranchAgentActivity?(repoPath: string): Promise<void>;
|
|
101
104
|
renameBranch?(repoPath: string, oldName: string, newName: string): Promise<void>;
|
|
102
105
|
setUpstreamBranch?(repoPath: string, name: string, upstream: string | undefined): Promise<void>;
|
|
103
106
|
setBranchDisposition?(
|
|
@@ -68,6 +68,7 @@ export interface IncomingActivityOptions extends GitLogOptionsBase {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
export interface GitCommitReachability {
|
|
71
|
+
readonly partial?: boolean;
|
|
71
72
|
readonly refs: (
|
|
72
73
|
| { readonly refType: 'branch'; readonly name: string; readonly remote: boolean; readonly current?: boolean }
|
|
73
74
|
| { readonly refType: 'tag'; readonly name: string; readonly current?: never }
|
|
@@ -77,6 +78,12 @@ export interface GitCommitReachability {
|
|
|
77
78
|
export interface GitCommitsSubProvider {
|
|
78
79
|
getCommit(repoPath: string, rev: string, cancellation?: AbortSignal): Promise<GitCommit | undefined>;
|
|
79
80
|
getCommitCount(repoPath: string, rev: string, cancellation?: AbortSignal): Promise<number | undefined>;
|
|
81
|
+
/** Cheap author/committer date lookup for a single revision. Skips the full commit parse (no files, parents, or message) — use when only the dates are needed. Pass a full SHA so caching stays correct (commits are immutable; refs are not). */
|
|
82
|
+
getCommitDates?(
|
|
83
|
+
repoPath: string,
|
|
84
|
+
rev: string,
|
|
85
|
+
cancellation?: AbortSignal,
|
|
86
|
+
): Promise<{ authorDate: Date; committerDate: Date } | undefined>;
|
|
80
87
|
getCommitFiles(repoPath: string, rev: string, cancellation?: AbortSignal): Promise<GitFileChange[]>;
|
|
81
88
|
getCommitForFile(
|
|
82
89
|
repoPath: string,
|
|
@@ -36,6 +36,8 @@ export type GkConfigKeys =
|
|
|
36
36
|
| `branch.${string}.gk-last-accessed`
|
|
37
37
|
/** `gk-last-modified` — ISO 8601 timestamp of when the branch last received a commit */
|
|
38
38
|
| `branch.${string}.gk-last-modified`
|
|
39
|
+
/** `gk-agent-last-activity` — ISO 8601 timestamp of when an AI agent was last active on this branch */
|
|
40
|
+
| `branch.${string}.gk-agent-last-activity`
|
|
39
41
|
/** `gk-disposition` — user-assigned branch disposition: 'starred' or 'archived' */
|
|
40
42
|
| `branch.${string}.gk-disposition`
|
|
41
43
|
/** `gk.defaultRemote` — the user-designated default remote for the repository */
|
|
@@ -32,7 +32,7 @@ export interface GitDiffSubProvider {
|
|
|
32
32
|
repoPath: string,
|
|
33
33
|
to?: string,
|
|
34
34
|
from?: string,
|
|
35
|
-
options?: { uris?: (string | Uri)[] },
|
|
35
|
+
options?: { uris?: (string | Uri)[]; includeUntracked?: boolean },
|
|
36
36
|
cancellation?: AbortSignal,
|
|
37
37
|
): Promise<GitDiffShortStat | undefined>;
|
|
38
38
|
getDiff?(
|
|
@@ -70,7 +70,13 @@ export interface GitDiffSubProvider {
|
|
|
70
70
|
repoPath: string,
|
|
71
71
|
ref1OrRange: string | GitRevisionRange,
|
|
72
72
|
ref2?: string,
|
|
73
|
-
options?: {
|
|
73
|
+
options?: {
|
|
74
|
+
filters?: GitDiffFilter[];
|
|
75
|
+
includeUntracked?: boolean;
|
|
76
|
+
path?: string;
|
|
77
|
+
renameLimit?: number;
|
|
78
|
+
similarityThreshold?: number;
|
|
79
|
+
},
|
|
74
80
|
): Promise<GitFile[] | undefined>;
|
|
75
81
|
getDiffTool?(repoPath?: string): Promise<string | undefined>;
|
|
76
82
|
getNextComparisonUris(
|
|
@@ -16,7 +16,7 @@ export interface GitOperationsSubProvider {
|
|
|
16
16
|
cherryPick(
|
|
17
17
|
repoPath: string,
|
|
18
18
|
revs: string[],
|
|
19
|
-
options?: { edit?: boolean; noCommit?: boolean },
|
|
19
|
+
options?: { edit?: boolean; noCommit?: boolean; source?: unknown },
|
|
20
20
|
): Promise<GitOperationResult>;
|
|
21
21
|
commit(
|
|
22
22
|
repoPath: string,
|
|
@@ -28,6 +28,7 @@ export interface GitOperationsSubProvider {
|
|
|
28
28
|
author?: string;
|
|
29
29
|
date?: string;
|
|
30
30
|
signoff?: boolean;
|
|
31
|
+
source?: unknown;
|
|
31
32
|
},
|
|
32
33
|
): Promise<void>;
|
|
33
34
|
fetch(
|
|
@@ -43,7 +44,7 @@ export interface GitOperationsSubProvider {
|
|
|
43
44
|
merge(
|
|
44
45
|
repoPath: string,
|
|
45
46
|
ref: string,
|
|
46
|
-
options?: { fastForward?: boolean | 'only'; noCommit?: boolean; squash?: boolean },
|
|
47
|
+
options?: { fastForward?: boolean | 'only'; noCommit?: boolean; squash?: boolean; source?: unknown },
|
|
47
48
|
): Promise<GitOperationResult>;
|
|
48
49
|
pull(
|
|
49
50
|
repoPath: string,
|
|
@@ -51,6 +52,7 @@ export interface GitOperationsSubProvider {
|
|
|
51
52
|
branch?: GitBranchReference | undefined;
|
|
52
53
|
rebase?: boolean | undefined;
|
|
53
54
|
tags?: boolean | undefined;
|
|
55
|
+
source?: unknown;
|
|
54
56
|
},
|
|
55
57
|
): Promise<void>;
|
|
56
58
|
push(
|
|
@@ -71,6 +73,7 @@ export interface GitOperationsSubProvider {
|
|
|
71
73
|
interactive?: boolean;
|
|
72
74
|
onto?: string;
|
|
73
75
|
updateRefs?: boolean;
|
|
76
|
+
source?: unknown;
|
|
74
77
|
},
|
|
75
78
|
): Promise<GitOperationResult>;
|
|
76
79
|
reset(
|
|
@@ -78,5 +81,9 @@ export interface GitOperationsSubProvider {
|
|
|
78
81
|
rev: string,
|
|
79
82
|
options?: { mode?: 'hard' | 'keep' | 'merge' | 'mixed' | 'soft' },
|
|
80
83
|
): Promise<void>;
|
|
81
|
-
revert(
|
|
84
|
+
revert(
|
|
85
|
+
repoPath: string,
|
|
86
|
+
refs: string[],
|
|
87
|
+
options?: { editMessage?: boolean; source?: unknown },
|
|
88
|
+
): Promise<GitOperationResult>;
|
|
82
89
|
}
|
|
@@ -17,7 +17,11 @@ export interface ResolvedRevision {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export interface GitRevisionSubProvider {
|
|
20
|
-
exists?(
|
|
20
|
+
exists?(
|
|
21
|
+
repoPath: string,
|
|
22
|
+
path: string,
|
|
23
|
+
revOrOptions?: string | { untracked?: 'only' | 'include' },
|
|
24
|
+
): Promise<boolean>;
|
|
21
25
|
getRevisionContent(repoPath: string, path: string, rev: string): Promise<Uint8Array | undefined>;
|
|
22
26
|
getSubmoduleHead?(repoPath: string, submodulePath: string): Promise<string | undefined>;
|
|
23
27
|
/** Gets tracked file paths from the index (reflects working tree state, even during rebase) */
|
|
@@ -19,4 +19,6 @@ export interface GitStagingSubProvider {
|
|
|
19
19
|
unstageFile(repoPath: string, pathOrUri: string | Uri): Promise<void>;
|
|
20
20
|
unstageFiles(repoPath: string, pathsOrUris: (string | Uri)[]): Promise<void>;
|
|
21
21
|
unstageDirectory(repoPath: string, directoryOrUri: string | Uri): Promise<void>;
|
|
22
|
+
stageAll(repoPath: string): Promise<void>;
|
|
23
|
+
unstageAll(repoPath: string): Promise<void>;
|
|
22
24
|
}
|
package/src/git/utils/sorting.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { sortCompare } from '../../utils/string.js';
|
|
2
|
+
import { compareByVersionDescending } from '../../utils/version.js';
|
|
2
3
|
import type { GitBranch } from '../models/branch.js';
|
|
3
4
|
import type { GitContributor } from '../models/contributor.js';
|
|
4
5
|
import type { GitRemote } from '../models/remote.js';
|
|
5
6
|
import type { GitTag } from '../models/tag.js';
|
|
6
7
|
import type { GitWorktree } from '../models/worktree.js';
|
|
8
|
+
import type { GitCommitReachability } from '../providers/commits.js';
|
|
7
9
|
|
|
8
10
|
export type BranchSorting = 'date:desc' | 'date:asc' | 'name:asc' | 'name:desc';
|
|
9
11
|
export type TagSorting = 'date:desc' | 'date:asc' | 'name:asc' | 'name:desc';
|
|
@@ -25,6 +27,25 @@ export interface BranchSortOptions {
|
|
|
25
27
|
openedWorktreesByBranch?: Set<string>;
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Comparator for sorting reachable refs to match `git for-each-ref` ordering: current first,
|
|
32
|
+
* local before remote, tags by version descending. Use with `.sort()` or `.toSorted()`.
|
|
33
|
+
*/
|
|
34
|
+
export function compareReachableRefs(
|
|
35
|
+
a: GitCommitReachability['refs'][number],
|
|
36
|
+
b: GitCommitReachability['refs'][number],
|
|
37
|
+
): number {
|
|
38
|
+
if (a.current && !b.current) return -1;
|
|
39
|
+
if (!a.current && b.current) return 1;
|
|
40
|
+
if (a.refType === 'branch' && b.refType === 'branch') {
|
|
41
|
+
if (a.remote !== b.remote) return a.remote ? 1 : -1;
|
|
42
|
+
}
|
|
43
|
+
if (a.refType === 'tag' && b.refType === 'tag') {
|
|
44
|
+
return compareByVersionDescending(a.name, b.name);
|
|
45
|
+
}
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
28
49
|
export function sortBranches(branches: GitBranch[], options?: BranchSortOptions): GitBranch[] {
|
|
29
50
|
options = { current: true, groupByType: true, orderBy: 'date:desc', ...options };
|
|
30
51
|
|
|
@@ -146,7 +146,7 @@ export class CliGitProvider implements GitProvider {
|
|
|
146
146
|
folderPath = joinPaths(parentPath, `${remoteName}-${count}`);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
await this._git.
|
|
149
|
+
await this._git.run({ cwd: parentPath }, 'clone', url, folderPath);
|
|
150
150
|
|
|
151
151
|
return folderPath;
|
|
152
152
|
}
|
package/src/git-cli/exec/git.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
ResetErrorReason,
|
|
18
18
|
RevertErrorReason,
|
|
19
19
|
ShowErrorReason,
|
|
20
|
+
SigningErrorReason,
|
|
20
21
|
StashApplyErrorReason,
|
|
21
22
|
StashPushErrorReason,
|
|
22
23
|
TagErrorReason,
|
|
@@ -24,6 +25,7 @@ import type {
|
|
|
24
25
|
WorktreeDeleteErrorReason,
|
|
25
26
|
} from '../../git/errors.js';
|
|
26
27
|
import { WorkspaceUntrustedError } from '../../git/errors.js';
|
|
28
|
+
import type { SigningFormat } from '../../git/models/signature.js';
|
|
27
29
|
import { CancellationError, getAbortSignalId, isCancellationError } from '../../utils/cancellation.js';
|
|
28
30
|
import { getScopedCounter } from '../../utils/counter.js';
|
|
29
31
|
import { getDurationMilliseconds, hrtime } from '../../utils/hrtime.js';
|
|
@@ -74,6 +76,8 @@ export const GitErrors = {
|
|
|
74
76
|
detachedHead: /You are in 'detached HEAD' state/i,
|
|
75
77
|
entryNotUpToDate: /error:\s*Entry ['"].+['"] not uptodate\. Cannot merge\./i,
|
|
76
78
|
failedToDeleteDirectoryNotEmpty: /failed to delete '(.*?)': Directory not empty/i,
|
|
79
|
+
gpgNotFound: /gpg:?\s*(?:command\s+)?not found|'gpg' is not recognized as|cannot run gpg:/i,
|
|
80
|
+
gpgSignFailed: /^error:\s*gpg failed to sign the data/im,
|
|
77
81
|
invalidName: /fatal:\s*'.+?' is not a valid branch name/i,
|
|
78
82
|
invalidLineCount: /file .+? has only (\d+) lines/i,
|
|
79
83
|
invalidObjectName: /invalid object name: (.*)\s/i,
|
|
@@ -106,6 +110,8 @@ export const GitErrors = {
|
|
|
106
110
|
remoteAhead: /rejected because the remote contains work/i,
|
|
107
111
|
remoteConnectionFailed: /Could not read from remote repository/i,
|
|
108
112
|
remoteRejected: /rejected because the remote contains work/i,
|
|
113
|
+
signingKeyNotAvailable: /secret key not available|no secret key|no signing key/i,
|
|
114
|
+
sshNotFound: /ssh-keygen[^\n]*(?:not found|No such file or directory|is not recognized)/i,
|
|
109
115
|
stashConflictingStagedAndUnstagedLines: /Cannot remove worktree changes/i,
|
|
110
116
|
stashNothingToSave: /No local changes to save/i,
|
|
111
117
|
stashSavedWorkingDirAndIndexState: /Saved working directory and index state/i,
|
|
@@ -413,6 +419,52 @@ export function getGitCommandError<T extends GitCommand, TReturn extends GitComm
|
|
|
413
419
|
return creator(undefined);
|
|
414
420
|
}
|
|
415
421
|
|
|
422
|
+
function extractSigningErrorText(ex: unknown): string {
|
|
423
|
+
if (ex == null) return '';
|
|
424
|
+
if (ex instanceof GitError) return ex.stderr || ex.stdout || ex.message || '';
|
|
425
|
+
if (ex instanceof Error) return ex.message || '';
|
|
426
|
+
if (typeof ex === 'string') return ex;
|
|
427
|
+
if (typeof ex === 'number' || typeof ex === 'boolean' || typeof ex === 'bigint') return String(ex);
|
|
428
|
+
if (typeof ex === 'object' && 'message' in ex && typeof ex.message === 'string') return ex.message;
|
|
429
|
+
return '';
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Classifies a Git error as a signing-related failure using the {@link GitErrors}
|
|
434
|
+
* signing regexes. Returns the matched {@link SigningErrorReason}, or `undefined`
|
|
435
|
+
* when the error is not a recognized signing failure.
|
|
436
|
+
*
|
|
437
|
+
* Precedence is significant: `passphraseFailed` (gpg sign failure) is checked
|
|
438
|
+
* before `noKey`, matching the ordering used historically in patch.ts — a
|
|
439
|
+
* combined stderr like "error: gpg failed to sign … gpg: No secret key"
|
|
440
|
+
* resolves to `passphraseFailed`, the outer cause.
|
|
441
|
+
*/
|
|
442
|
+
export function classifySigningError(ex: unknown): SigningErrorReason | undefined {
|
|
443
|
+
const text = extractSigningErrorText(ex);
|
|
444
|
+
if (!text) return undefined;
|
|
445
|
+
if (GitErrors.gpgSignFailed.test(text)) return 'passphraseFailed';
|
|
446
|
+
if (GitErrors.signingKeyNotAvailable.test(text)) return 'noKey';
|
|
447
|
+
if (GitErrors.gpgNotFound.test(text)) return 'gpgNotFound';
|
|
448
|
+
if (GitErrors.sshNotFound.test(text)) return 'sshNotFound';
|
|
449
|
+
return undefined;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Infers the {@link SigningFormat} from stderr hints (e.g., mentions of
|
|
454
|
+
* `ssh-keygen` or `gpg.ssh.*` config keys). Returns `undefined` when no hints
|
|
455
|
+
* are present so callers can supply their own default (typically `'gpg'`).
|
|
456
|
+
*
|
|
457
|
+
* Used as a fallback when `config.getSigningConfig` is unavailable or rejects
|
|
458
|
+
* on the error path.
|
|
459
|
+
*/
|
|
460
|
+
export function inferSigningFormatFromError(ex: unknown): SigningFormat | undefined {
|
|
461
|
+
const text = extractSigningErrorText(ex);
|
|
462
|
+
if (!text) return undefined;
|
|
463
|
+
if (/\bssh-keygen\b|gpg\.ssh\.(?:program|allowedsignersfile)/i.test(text)) return 'ssh';
|
|
464
|
+
if (/\bgpg\b/i.test(text)) return 'gpg';
|
|
465
|
+
return undefined;
|
|
466
|
+
}
|
|
467
|
+
|
|
416
468
|
export interface GitOptions {
|
|
417
469
|
/** Custom environment variables to add to every git command */
|
|
418
470
|
env?: Record<string, string | undefined>;
|
|
@@ -579,15 +631,15 @@ export class Git {
|
|
|
579
631
|
);
|
|
580
632
|
}
|
|
581
633
|
|
|
582
|
-
async
|
|
634
|
+
async run(
|
|
583
635
|
options: ExitCodeOnlyGitCommandOptions,
|
|
584
636
|
...args: readonly (string | undefined)[]
|
|
585
637
|
): Promise<GitResult<unknown>>;
|
|
586
|
-
async
|
|
638
|
+
async run<T extends string | Buffer = string>(
|
|
587
639
|
options: GitExecOptions,
|
|
588
640
|
...args: readonly (string | undefined)[]
|
|
589
641
|
): Promise<GitResult<T>>;
|
|
590
|
-
async
|
|
642
|
+
async run<T extends string | Buffer = string>(
|
|
591
643
|
options: GitExecOptions,
|
|
592
644
|
...args: readonly (string | undefined)[]
|
|
593
645
|
): Promise<GitResult<T | unknown>> {
|
|
@@ -602,7 +654,7 @@ export class Git {
|
|
|
602
654
|
options.caching.commonPath ?? options.cwd!,
|
|
603
655
|
gitCommand,
|
|
604
656
|
async cacheable => {
|
|
605
|
-
const result = await this.
|
|
657
|
+
const result = await this.runCore<T>({ ...options, caching: undefined }, runArgs, gitCommand);
|
|
606
658
|
if (result.exitCode !== 0) {
|
|
607
659
|
cacheable.invalidate();
|
|
608
660
|
}
|
|
@@ -612,10 +664,10 @@ export class Git {
|
|
|
612
664
|
);
|
|
613
665
|
}
|
|
614
666
|
|
|
615
|
-
return this.
|
|
667
|
+
return this.runCore<T>(options, runArgs, gitCommand);
|
|
616
668
|
}
|
|
617
669
|
|
|
618
|
-
private async
|
|
670
|
+
private async runCore<T extends string | Buffer>(
|
|
619
671
|
options: GitExecOptions,
|
|
620
672
|
args: string[],
|
|
621
673
|
gitCommand: string,
|
|
@@ -679,7 +731,7 @@ export class Git {
|
|
|
679
731
|
// Execute through the queue (interactive/normal run immediately, background is throttled)
|
|
680
732
|
const gitPath = await this.path();
|
|
681
733
|
void this._queue
|
|
682
|
-
.
|
|
734
|
+
.run(priority, () => runSpawn<T>(gitPath, args, encoding ?? 'utf8', runOpts), cancellation)
|
|
683
735
|
.then(deferred.fulfill, (e: unknown) => deferred.cancel(e instanceof Error ? e : new Error(String(e))))
|
|
684
736
|
.finally(() => {
|
|
685
737
|
this.pendingCommands.delete(cacheKey);
|
|
@@ -695,8 +747,8 @@ export class Git {
|
|
|
695
747
|
try {
|
|
696
748
|
result = await promise;
|
|
697
749
|
return {
|
|
698
|
-
stdout: result.stdout
|
|
699
|
-
stderr: result.stderr
|
|
750
|
+
stdout: result.stdout,
|
|
751
|
+
stderr: result.stderr,
|
|
700
752
|
exitCode: result.exitCode ?? 0,
|
|
701
753
|
};
|
|
702
754
|
} catch (ex) {
|
|
@@ -723,15 +775,15 @@ export class Git {
|
|
|
723
775
|
if (errorHandling === 'ignore') {
|
|
724
776
|
if (ex instanceof RunError) {
|
|
725
777
|
return {
|
|
726
|
-
stdout: ex.stdout
|
|
727
|
-
stderr: ex.stderr
|
|
778
|
+
stdout: ex.stdout,
|
|
779
|
+
stderr: ex.stderr,
|
|
728
780
|
exitCode: ex.code != null ? (typeof ex.code === 'number' ? ex.code : parseInt(ex.code, 10)) : 0,
|
|
729
781
|
cancelled: ex instanceof CancelledRunError,
|
|
730
782
|
};
|
|
731
783
|
}
|
|
732
784
|
|
|
733
785
|
return {
|
|
734
|
-
stdout: ''
|
|
786
|
+
stdout: '',
|
|
735
787
|
stderr: undefined,
|
|
736
788
|
exitCode: 0,
|
|
737
789
|
cancelled: ex instanceof CancelledRunError,
|
|
@@ -747,7 +799,7 @@ export class Git {
|
|
|
747
799
|
|
|
748
800
|
defaultExceptionHandler(exception, options.cwd, start);
|
|
749
801
|
exception = undefined;
|
|
750
|
-
return { stdout: ''
|
|
802
|
+
return { stdout: '', stderr: result?.stderr, exitCode: result?.exitCode ?? 0 };
|
|
751
803
|
} finally {
|
|
752
804
|
this.logGitCommandComplete(gitCommand, exception, getDurationMilliseconds(start), waiting);
|
|
753
805
|
}
|
|
@@ -888,7 +940,7 @@ export class Git {
|
|
|
888
940
|
for await (const chunk of proc.stdout) {
|
|
889
941
|
buffers.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
890
942
|
}
|
|
891
|
-
yield await decode(Buffer.concat(buffers
|
|
943
|
+
yield await decode(Buffer.concat(buffers), { encoding: enc });
|
|
892
944
|
}
|
|
893
945
|
}
|
|
894
946
|
} finally {
|
|
@@ -914,7 +966,7 @@ export class Git {
|
|
|
914
966
|
}
|
|
915
967
|
|
|
916
968
|
async rev_parse__git_dir(cwd: string): Promise<{ path: string; commonPath?: string } | undefined> {
|
|
917
|
-
const result = await this.
|
|
969
|
+
const result = await this.run({ cwd: cwd, errors: 'ignore' }, 'rev-parse', '--git-dir', '--git-common-dir');
|
|
918
970
|
if (!result.stdout) return undefined;
|
|
919
971
|
|
|
920
972
|
// Keep trailing spaces which are part of the directory name
|
|
@@ -946,7 +998,7 @@ export class Git {
|
|
|
946
998
|
// Check if the folder is a bare clone: if it has a file named HEAD && `rev-parse --show-cdup` is empty
|
|
947
999
|
if (await fsExists(joinPaths(cwd, 'HEAD'))) {
|
|
948
1000
|
try {
|
|
949
|
-
result = await this.
|
|
1001
|
+
result = await this.run(
|
|
950
1002
|
{ cwd: cwd, errors: 'throw', configs: ['-C', cwd] },
|
|
951
1003
|
'rev-parse',
|
|
952
1004
|
'--show-cdup',
|
|
@@ -962,7 +1014,7 @@ export class Git {
|
|
|
962
1014
|
}
|
|
963
1015
|
|
|
964
1016
|
try {
|
|
965
|
-
result = await this.
|
|
1017
|
+
result = await this.run({ cwd: cwd, errors: 'throw' }, 'rev-parse', '--show-toplevel');
|
|
966
1018
|
// Make sure to normalize: https://github.com/git-for-windows/git/issues/2478
|
|
967
1019
|
// Keep trailing spaces which are part of the directory name
|
|
968
1020
|
return !result.stdout
|
|
@@ -985,7 +1037,7 @@ export class Git {
|
|
|
985
1037
|
const inDotGit = GitWarnings.mustRunInWorkTree.test(ex.stderr ?? '');
|
|
986
1038
|
// Check if we are in a bare clone
|
|
987
1039
|
if (inDotGit && this.options.isTrusted?.() !== false) {
|
|
988
|
-
result = await this.
|
|
1040
|
+
result = await this.run({ cwd: cwd, errors: 'ignore' }, 'rev-parse', '--is-bare-repository');
|
|
989
1041
|
if (result.stdout.trim() === 'true') {
|
|
990
1042
|
const result = await this.rev_parse__git_dir(cwd);
|
|
991
1043
|
const repoPath = result?.commonPath ?? result?.path;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { GitCommandPriority } from './exec.types.js';
|
|
2
2
|
|
|
3
3
|
interface QueuedCommand {
|
|
4
|
-
|
|
4
|
+
run: () => Promise<unknown>;
|
|
5
5
|
resolve: (value: unknown) => void;
|
|
6
6
|
reject: (reason: unknown) => void;
|
|
7
7
|
queuedAt: number;
|
|
8
8
|
priority: GitCommandPriority;
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
abortHandler?: () => void;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
/** Priority levels in descending order (highest first) */
|
|
@@ -14,6 +16,10 @@ const priorities: GitCommandPriority[] = ['interactive', 'normal', 'background']
|
|
|
14
16
|
/** How many extra slots interactive commands can use when at capacity */
|
|
15
17
|
const interactiveBurstCapacity = 2;
|
|
16
18
|
|
|
19
|
+
function abortReason(signal: AbortSignal): Error {
|
|
20
|
+
return signal.reason instanceof Error ? signal.reason : new Error('Aborted');
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
export interface GitQueueConfig {
|
|
18
24
|
/** Maximum number of concurrent git processes. Defaults to 7. */
|
|
19
25
|
maxConcurrent?: number;
|
|
@@ -67,6 +73,9 @@ export class GitQueue {
|
|
|
67
73
|
this._disposed = true;
|
|
68
74
|
for (const queue of this._queues.values()) {
|
|
69
75
|
for (const cmd of queue) {
|
|
76
|
+
if (cmd.signal != null && cmd.abortHandler != null) {
|
|
77
|
+
cmd.signal.removeEventListener('abort', cmd.abortHandler);
|
|
78
|
+
}
|
|
70
79
|
cmd.reject(new Error('GitQueue disposed'));
|
|
71
80
|
}
|
|
72
81
|
queue.length = 0;
|
|
@@ -89,7 +98,7 @@ export class GitQueue {
|
|
|
89
98
|
}
|
|
90
99
|
|
|
91
100
|
/** Check if a command at the given priority can execute immediately */
|
|
92
|
-
private
|
|
101
|
+
private canRunNow(priority: GitCommandPriority): boolean {
|
|
93
102
|
// Must yield to higher priority waiting
|
|
94
103
|
if (this.hasHigherPriorityWaiting(priority)) return false;
|
|
95
104
|
|
|
@@ -115,20 +124,32 @@ export class GitQueue {
|
|
|
115
124
|
return false;
|
|
116
125
|
}
|
|
117
126
|
|
|
118
|
-
/**
|
|
119
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Execute a git command with the specified priority.
|
|
129
|
+
*
|
|
130
|
+
* When `signal` is provided:
|
|
131
|
+
* - If already aborted, rejects immediately without running.
|
|
132
|
+
* - If aborted while queued, the command is removed from the queue and rejected before it ever runs.
|
|
133
|
+
* - If aborted while running, the in-flight spawn must honor the same signal separately
|
|
134
|
+
* (callers pass it via `runOpts.cancellation`); the queue does not interrupt running work.
|
|
135
|
+
*/
|
|
136
|
+
run<T>(priority: GitCommandPriority, fn: () => Promise<T>, signal?: AbortSignal): Promise<T> {
|
|
120
137
|
if (this._disposed) {
|
|
121
138
|
return Promise.reject(new Error('GitQueue disposed'));
|
|
122
139
|
}
|
|
123
140
|
|
|
124
|
-
if (
|
|
125
|
-
return
|
|
141
|
+
if (signal?.aborted) {
|
|
142
|
+
return Promise.reject(abortReason(signal));
|
|
126
143
|
}
|
|
127
144
|
|
|
128
|
-
|
|
145
|
+
if (!this.canRunNow(priority)) {
|
|
146
|
+
return this.enqueue(fn, priority, signal);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return this.runcore(fn);
|
|
129
150
|
}
|
|
130
151
|
|
|
131
|
-
private async
|
|
152
|
+
private async runcore<T>(fn: () => Promise<T>): Promise<T> {
|
|
132
153
|
this._activeCount++;
|
|
133
154
|
try {
|
|
134
155
|
return await fn();
|
|
@@ -138,7 +159,7 @@ export class GitQueue {
|
|
|
138
159
|
}
|
|
139
160
|
}
|
|
140
161
|
|
|
141
|
-
private enqueue<T>(fn: () => Promise<T>, priority: GitCommandPriority): Promise<T> {
|
|
162
|
+
private enqueue<T>(fn: () => Promise<T>, priority: GitCommandPriority, signal?: AbortSignal): Promise<T> {
|
|
142
163
|
const queue = this._queues.get(priority)!;
|
|
143
164
|
const maxDepth = this._config.maxQueueDepth ?? 500;
|
|
144
165
|
if (maxDepth > 0 && queue.length >= maxDepth) {
|
|
@@ -146,13 +167,29 @@ export class GitQueue {
|
|
|
146
167
|
}
|
|
147
168
|
|
|
148
169
|
return new Promise<T>((resolve, reject) => {
|
|
149
|
-
|
|
150
|
-
|
|
170
|
+
const cmd: QueuedCommand = {
|
|
171
|
+
run: fn,
|
|
151
172
|
resolve: resolve as (value: unknown) => void,
|
|
152
173
|
reject: reject,
|
|
153
174
|
queuedAt: Date.now(),
|
|
154
175
|
priority: priority,
|
|
155
|
-
|
|
176
|
+
signal: signal,
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
if (signal != null) {
|
|
180
|
+
cmd.abortHandler = () => {
|
|
181
|
+
const idx = queue.indexOf(cmd);
|
|
182
|
+
// If still queued, remove and reject so it never runs.
|
|
183
|
+
// If already dequeued, the running command should honor the signal at its own layer.
|
|
184
|
+
if (idx !== -1) {
|
|
185
|
+
queue.splice(idx, 1);
|
|
186
|
+
cmd.reject(abortReason(signal));
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
signal.addEventListener('abort', cmd.abortHandler, { once: true });
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
queue.push(cmd);
|
|
156
193
|
});
|
|
157
194
|
}
|
|
158
195
|
|
|
@@ -172,6 +209,13 @@ export class GitQueue {
|
|
|
172
209
|
}
|
|
173
210
|
|
|
174
211
|
private runQueued(cmd: QueuedCommand): void {
|
|
212
|
+
// Detach the abort listener now that the command has left the queue — any subsequent
|
|
213
|
+
// abort must be handled by the running spawn itself (via runOpts.cancellation).
|
|
214
|
+
if (cmd.signal != null && cmd.abortHandler != null) {
|
|
215
|
+
cmd.signal.removeEventListener('abort', cmd.abortHandler);
|
|
216
|
+
cmd.abortHandler = undefined;
|
|
217
|
+
}
|
|
218
|
+
|
|
175
219
|
const waitTime = Date.now() - cmd.queuedAt;
|
|
176
220
|
if (waitTime > 1000) {
|
|
177
221
|
this._hooks.onSlowQueue?.({
|
|
@@ -189,7 +233,7 @@ export class GitQueue {
|
|
|
189
233
|
|
|
190
234
|
this._activeCount++;
|
|
191
235
|
try {
|
|
192
|
-
cmd.
|
|
236
|
+
cmd.run()
|
|
193
237
|
.then(cmd.resolve, cmd.reject)
|
|
194
238
|
.finally(() => {
|
|
195
239
|
this._activeCount--;
|
|
@@ -176,6 +176,10 @@ const stashMapping = {
|
|
|
176
176
|
parents: '%P',
|
|
177
177
|
stashName: '%gd',
|
|
178
178
|
summary: '%gs',
|
|
179
|
+
// %s (commit subject) is git's authoritative `On <branch>: …` / `WIP on <branch>: …` record,
|
|
180
|
+
// present even when the reflog message (%gs) was customized (autostash, `git stash store -m`).
|
|
181
|
+
// Used downstream to extract `stashOnRef` reliably.
|
|
182
|
+
commitSubject: '%s',
|
|
179
183
|
};
|
|
180
184
|
|
|
181
185
|
type StashLogParser = LogParser<typeof stashMapping>;
|
|
@@ -882,7 +886,7 @@ function createLogParserWithPatch<T extends Record<string, string>>(
|
|
|
882
886
|
}
|
|
883
887
|
|
|
884
888
|
return {
|
|
885
|
-
status: (fileMatch[1] === 'rename' ? 'R' : 'M')
|
|
889
|
+
status: (fileMatch[1] === 'rename' ? 'R' : 'M') satisfies GitFileIndexStatus,
|
|
886
890
|
path: fileMatch[2],
|
|
887
891
|
originalPath: fileMatch[1] === 'rename' ? fileMatch[3] : undefined,
|
|
888
892
|
range: range,
|
|
@@ -393,7 +393,7 @@ export class BlameGitSubProvider implements GitBlameSubProvider {
|
|
|
393
393
|
const { root, file, params, stdin } = await this.buildBlameArgs(repoPath, fileName, options);
|
|
394
394
|
|
|
395
395
|
try {
|
|
396
|
-
return await this.git.
|
|
396
|
+
return await this.git.run({ cwd: root, stdin: stdin }, ...params, '--', file);
|
|
397
397
|
} catch (ex) {
|
|
398
398
|
// Since `-c blame.ignoreRevsFile=` doesn't work (despite what the docs suggest),
|
|
399
399
|
// detect the error and throw a more helpful one
|