git-chopstick-core 0.1.2 → 0.1.4

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 (145) hide show
  1. package/README.md +42 -10
  2. package/dist/git/apply.d.ts +1 -1
  3. package/dist/git/apply.js +1 -1
  4. package/dist/git/apply.js.map +1 -1
  5. package/dist/git/environment.d.ts +1 -1
  6. package/dist/git/environment.js +1 -1
  7. package/dist/git/environment.js.map +1 -1
  8. package/dist/git/exec.js.map +1 -1
  9. package/dist/git/gitignore.js +1 -1
  10. package/dist/git/gitignore.js.map +1 -1
  11. package/dist/git/index.d.ts +1 -0
  12. package/dist/git/index.js +3 -0
  13. package/dist/git/index.js.map +1 -1
  14. package/dist/lib/fatal-error.d.ts +1 -1
  15. package/dist/lib/fatal-error.js +1 -1
  16. package/dist/lib/fatal-error.js.map +1 -1
  17. package/dist/lib/progress/from-process.js.map +1 -1
  18. package/dist/lib/progress/index.d.ts +5 -5
  19. package/dist/lib/progress/index.js +5 -5
  20. package/dist/lib/progress/index.js.map +1 -1
  21. package/dist/lib/progress/revert.d.ts +1 -1
  22. package/dist/lib/progress/revert.js +1 -1
  23. package/dist/lib/progress/revert.js.map +1 -1
  24. package/dist/lib/status-parser.js +0 -12
  25. package/dist/lib/status-parser.js.map +1 -1
  26. package/dist/models/repository.d.ts +1 -1
  27. package/dist/models/repository.js +1 -1
  28. package/dist/models/repository.js.map +1 -1
  29. package/package.json +39 -9
  30. package/src/git/add.ts +0 -16
  31. package/src/git/apply.ts +0 -154
  32. package/src/git/authentication.ts +0 -20
  33. package/src/git/branch.ts +0 -206
  34. package/src/git/checkout-index.ts +0 -40
  35. package/src/git/checkout.ts +0 -235
  36. package/src/git/cherry-pick.ts +0 -504
  37. package/src/git/clean.ts +0 -9
  38. package/src/git/clone.ts +0 -86
  39. package/src/git/coerce-to-buffer.ts +0 -4
  40. package/src/git/coerce-to-string.ts +0 -4
  41. package/src/git/commit.ts +0 -136
  42. package/src/git/config.ts +0 -392
  43. package/src/git/core.ts +0 -625
  44. package/src/git/create-tail-stream.ts +0 -36
  45. package/src/git/credential.ts +0 -83
  46. package/src/git/description.ts +0 -33
  47. package/src/git/diff-check.ts +0 -27
  48. package/src/git/diff-index.ts +0 -116
  49. package/src/git/diff.ts +0 -880
  50. package/src/git/environment.ts +0 -116
  51. package/src/git/exec.ts +0 -285
  52. package/src/git/fetch.ts +0 -141
  53. package/src/git/for-each-ref.ts +0 -160
  54. package/src/git/format-patch.ts +0 -17
  55. package/src/git/git-delimiter-parser.ts +0 -95
  56. package/src/git/gitignore.ts +0 -157
  57. package/src/git/index.ts +0 -46
  58. package/src/git/init.ts +0 -11
  59. package/src/git/interpret-trailers.ts +0 -176
  60. package/src/git/lfs.ts +0 -100
  61. package/src/git/log.ts +0 -376
  62. package/src/git/merge-tree.ts +0 -42
  63. package/src/git/merge.ts +0 -154
  64. package/src/git/multi-operation-terminal-output.ts +0 -68
  65. package/src/git/pull.ts +0 -130
  66. package/src/git/push-terminal-chunk.ts +0 -41
  67. package/src/git/push.ts +0 -119
  68. package/src/git/rebase.ts +0 -627
  69. package/src/git/reflog.ts +0 -127
  70. package/src/git/refs.ts +0 -63
  71. package/src/git/remote.ts +0 -143
  72. package/src/git/reorder.ts +0 -153
  73. package/src/git/reset.ts +0 -101
  74. package/src/git/rev-list.ts +0 -201
  75. package/src/git/rev-parse.ts +0 -92
  76. package/src/git/revert.ts +0 -55
  77. package/src/git/rm.ts +0 -31
  78. package/src/git/show.ts +0 -88
  79. package/src/git/spawn.ts +0 -38
  80. package/src/git/squash.ts +0 -173
  81. package/src/git/stage.ts +0 -97
  82. package/src/git/stash.ts +0 -302
  83. package/src/git/status.ts +0 -502
  84. package/src/git/submodule.ts +0 -212
  85. package/src/git/tag.ts +0 -134
  86. package/src/git/update-index.ts +0 -169
  87. package/src/git/update-ref.ts +0 -50
  88. package/src/git/var.ts +0 -42
  89. package/src/git/worktree-include.ts +0 -146
  90. package/src/git/worktree.ts +0 -219
  91. package/src/index.ts +0 -11
  92. package/src/lib/api.ts +0 -7
  93. package/src/lib/diff-parser.ts +0 -249
  94. package/src/lib/directory-exists.ts +0 -10
  95. package/src/lib/errno-exception.ts +0 -12
  96. package/src/lib/fatal-error.ts +0 -23
  97. package/src/lib/feature-flag.ts +0 -29
  98. package/src/lib/file-system.ts +0 -7
  99. package/src/lib/get-old-path.ts +0 -11
  100. package/src/lib/git/environment.ts +0 -14
  101. package/src/lib/git-perf.ts +0 -3
  102. package/src/lib/helpers/default-branch.ts +0 -3
  103. package/src/lib/helpers/path.ts +0 -5
  104. package/src/lib/hooks/with-hooks-env.ts +0 -7
  105. package/src/lib/merge.ts +0 -3
  106. package/src/lib/noop.ts +0 -1
  107. package/src/lib/patch-formatter.ts +0 -18
  108. package/src/lib/path-exists.ts +0 -7
  109. package/src/lib/progress/from-process.ts +0 -10
  110. package/src/lib/progress/index.ts +0 -43
  111. package/src/lib/progress/revert.ts +0 -17
  112. package/src/lib/rebase.ts +0 -3
  113. package/src/lib/remove-remote-prefix.ts +0 -4
  114. package/src/lib/resolve-git-proxy.ts +0 -3
  115. package/src/lib/round.ts +0 -4
  116. package/src/lib/split-buffer.ts +0 -14
  117. package/src/lib/status-parser.ts +0 -188
  118. package/src/lib/stores/helpers/find-default-remote.ts +0 -3
  119. package/src/lib/trampoline/trampoline-environment.ts +0 -8
  120. package/src/models/branch.ts +0 -78
  121. package/src/models/cherry-pick.ts +0 -12
  122. package/src/models/clone-options.ts +0 -6
  123. package/src/models/commit-identity.ts +0 -35
  124. package/src/models/commit.ts +0 -44
  125. package/src/models/computed-action.ts +0 -6
  126. package/src/models/diff/diff-data.ts +0 -78
  127. package/src/models/diff/diff-line.ts +0 -36
  128. package/src/models/diff/diff-selection.ts +0 -165
  129. package/src/models/diff/image-diff.ts +0 -6
  130. package/src/models/diff/image.ts +0 -8
  131. package/src/models/diff/index.ts +0 -6
  132. package/src/models/diff/raw-diff.ts +0 -41
  133. package/src/models/git-author.ts +0 -16
  134. package/src/models/index.ts +0 -36
  135. package/src/models/manual-conflict-resolution.ts +0 -4
  136. package/src/models/merge.ts +0 -6
  137. package/src/models/multi-commit-operation.ts +0 -6
  138. package/src/models/progress.ts +0 -67
  139. package/src/models/rebase.ts +0 -20
  140. package/src/models/remote.ts +0 -10
  141. package/src/models/repository.ts +0 -16
  142. package/src/models/stash-entry.ts +0 -25
  143. package/src/models/status.ts +0 -275
  144. package/src/models/submodule.ts +0 -13
  145. package/src/models/worktree.ts +0 -11
package/src/git/log.ts DELETED
@@ -1,376 +0,0 @@
1
- import { git } from './core.js'
2
- import {
3
- CommittedFileChange,
4
- AppFileStatusKind,
5
- PlainFileStatus,
6
- CopiedOrRenamedFileStatus,
7
- UntrackedFileStatus,
8
- AppFileStatus,
9
- SubmoduleStatus,
10
- } from '../models/status.js'
11
- import { Repository } from '../models/repository.js'
12
- import { Commit } from '../models/commit.js'
13
- import { CommitIdentity } from '../models/commit-identity.js'
14
- import { parseRawUnfoldedTrailers } from './interpret-trailers.js'
15
- import { createLogParser } from './git-delimiter-parser.js'
16
- import { forceUnwrap } from '../lib/fatal-error.js'
17
- import assert from 'assert'
18
-
19
- // File mode 160000 is used by git specifically for submodules:
20
- // https://github.com/git/git/blob/v2.37.3/cache.h#L62-L69
21
- const SubmoduleFileMode = '160000'
22
-
23
- function mapSubmoduleStatusFileModes(
24
- status: string,
25
- srcMode: string,
26
- dstMode: string
27
- ): SubmoduleStatus | undefined {
28
- return srcMode === SubmoduleFileMode &&
29
- dstMode === SubmoduleFileMode &&
30
- status === 'M'
31
- ? {
32
- commitChanged: true,
33
- untrackedChanges: false,
34
- modifiedChanges: false,
35
- }
36
- : (srcMode === SubmoduleFileMode && status === 'D') ||
37
- (dstMode === SubmoduleFileMode && status === 'A')
38
- ? {
39
- commitChanged: false,
40
- untrackedChanges: false,
41
- modifiedChanges: false,
42
- }
43
- : undefined
44
- }
45
-
46
- /**
47
- * Map the raw status text from Git to an app-friendly value
48
- * shamelessly borrowed from GitHub Desktop (Windows)
49
- */
50
- function mapStatus(
51
- rawStatus: string,
52
- oldPath: string | undefined,
53
- srcMode: string,
54
- dstMode: string
55
- ): PlainFileStatus | CopiedOrRenamedFileStatus | UntrackedFileStatus {
56
- const status = rawStatus.trim()
57
- const submoduleStatus = mapSubmoduleStatusFileModes(status, srcMode, dstMode)
58
-
59
- if (status === 'M') {
60
- return { kind: AppFileStatusKind.Modified, submoduleStatus }
61
- } // modified
62
- if (status === 'A') {
63
- return { kind: AppFileStatusKind.New, submoduleStatus }
64
- } // added
65
- if (status === '?') {
66
- return { kind: AppFileStatusKind.Untracked, submoduleStatus }
67
- } // untracked
68
- if (status === 'D') {
69
- return { kind: AppFileStatusKind.Deleted, submoduleStatus }
70
- } // deleted
71
- if (status === 'R' && oldPath != null) {
72
- return {
73
- kind: AppFileStatusKind.Renamed,
74
- oldPath,
75
- submoduleStatus,
76
- renameIncludesModifications: false,
77
- }
78
- } // renamed
79
- if (status === 'C' && oldPath != null) {
80
- return {
81
- kind: AppFileStatusKind.Copied,
82
- oldPath,
83
- submoduleStatus,
84
- renameIncludesModifications: false,
85
- }
86
- } // copied
87
-
88
- // git log -M --name-status will return a RXXX - where XXX is a percentage
89
- if (status.match(/R[0-9]+/) && oldPath != null) {
90
- return {
91
- kind: AppFileStatusKind.Renamed,
92
- oldPath,
93
- submoduleStatus,
94
- renameIncludesModifications: status !== 'R100',
95
- }
96
- }
97
-
98
- // git log -C --name-status will return a CXXX - where XXX is a percentage
99
- if (status.match(/C[0-9]+/) && oldPath != null) {
100
- return {
101
- kind: AppFileStatusKind.Copied,
102
- oldPath,
103
- submoduleStatus,
104
- renameIncludesModifications: false,
105
- }
106
- }
107
-
108
- return { kind: AppFileStatusKind.Modified, submoduleStatus }
109
- }
110
-
111
- const isCopyOrRename = (
112
- status: AppFileStatus
113
- ): status is CopiedOrRenamedFileStatus =>
114
- status.kind === AppFileStatusKind.Copied ||
115
- status.kind === AppFileStatusKind.Renamed
116
-
117
- /**
118
- * Get the repository's commits using `revisionRange` and limited to `limit`
119
- */
120
- export async function getCommits(
121
- repository: Repository,
122
- revisionRange?: string,
123
- limit?: number,
124
- skip?: number,
125
- additionalArgs: ReadonlyArray<string> = []
126
- ): Promise<ReadonlyArray<Commit>> {
127
- const { formatArgs, parse } = createLogParser({
128
- sha: '%H', // SHA
129
- shortSha: '%h', // short SHA
130
- summary: '%s', // summary
131
- body: '%b', // body
132
- // author identity string, matching format of GIT_AUTHOR_IDENT.
133
- // author name <author email> <author date>
134
- // author date format dependent on --date arg, should be raw
135
- author: '%an <%ae> %ad',
136
- committer: '%cn <%ce> %cd',
137
- parents: '%P', // parent SHAs,
138
- trailers: '%(trailers:unfold,only)',
139
- refs: '%D',
140
- })
141
-
142
- const args = ['log']
143
-
144
- if (revisionRange !== undefined) {
145
- args.push(revisionRange)
146
- }
147
-
148
- args.push('--date=raw')
149
-
150
- if (limit !== undefined) {
151
- args.push(`--max-count=${limit}`)
152
- }
153
-
154
- if (skip !== undefined) {
155
- args.push(`--skip=${skip}`)
156
- }
157
-
158
- args.push(
159
- ...formatArgs,
160
- '--no-show-signature',
161
- '--no-color',
162
- ...additionalArgs,
163
- '--'
164
- )
165
- const result = await git(args, repository.path, 'getCommits', {
166
- successExitCodes: new Set([0, 128]),
167
- encoding: 'buffer',
168
- })
169
-
170
- // if the repository has an unborn HEAD, return an empty history of commits
171
- if (result.exitCode === 128) {
172
- return new Array<Commit>()
173
- }
174
-
175
- const parsed = parse(result.stdout)
176
-
177
- return parsed.map(commit => {
178
- // Ref is of the format: (HEAD -> master, tag: some-tag-name, tag: some-other-tag,with-a-comma, origin/master, origin/HEAD)
179
- // Refs are comma separated, but some like tags can also contain commas in the name, so we split on the pattern ", " and then
180
- // check each ref for the tag prefix. We used to use the regex /tag: ([^\s,]+)/g)`, but will clip a tag with a comma short.
181
- const tags = commit.refs
182
- .toString()
183
- .split(', ')
184
- .flatMap(ref => (ref.startsWith('tag: ') ? ref.substring(5) : []))
185
-
186
- return new Commit(
187
- commit.sha.toString(),
188
- commit.shortSha.toString(),
189
- commit.summary.subarray(0, 100 * 1024).toString(),
190
- commit.body.subarray(0, 100 * 1024).toString(),
191
- CommitIdentity.parseIdentity(commit.author.toString()),
192
- CommitIdentity.parseIdentity(commit.committer.toString()),
193
- commit.parents.length > 0 ? commit.parents.toString().split(' ') : [],
194
- // We know for sure that the trailer separator will be ':' since we got
195
- // them from %(trailers:unfold) above, see `git help log`:
196
- //
197
- // "key_value_separator=<SEP>: specify a separator inserted between
198
- // trailer lines. When this option is not given each trailer key-value
199
- // pair is separated by ": ". Otherwise it shares the same semantics as
200
- // separator=<SEP> above."
201
- parseRawUnfoldedTrailers(commit.trailers.toString(), ':'),
202
- tags
203
- )
204
- })
205
- }
206
-
207
- /** This interface contains information of a changeset. */
208
- export interface IChangesetData {
209
- /** Files changed in the changeset. */
210
- readonly files: ReadonlyArray<CommittedFileChange>
211
-
212
- /** Number of lines added in the changeset. */
213
- readonly linesAdded: number
214
-
215
- /** Number of lines deleted in the changeset. */
216
- readonly linesDeleted: number
217
- }
218
-
219
- /** Get the files that were changed in the given commit. */
220
- export async function getChangedFiles(
221
- repository: Repository,
222
- sha: string
223
- ): Promise<IChangesetData> {
224
- // opt-in for rename detection (-M) and copies detection (-C)
225
- // this is equivalent to the user configuring 'diff.renames' to 'copies'
226
- // NOTE: order here matters - doing -M before -C means copies aren't detected
227
- const args = [
228
- 'log',
229
- sha,
230
- '-C',
231
- '-M',
232
- '-m',
233
- '-1',
234
- '--no-show-signature',
235
- '--first-parent',
236
- '--raw',
237
- '--format=format:',
238
- '--numstat',
239
- '-z',
240
- '--',
241
- ]
242
-
243
- const { stdout } = await git(args, repository.path, 'getChangesFiles')
244
- return parseRawLogWithNumstat(stdout, sha, `${sha}^`)
245
- }
246
-
247
- /**
248
- * Parses output of diff flags -z --raw --numstat.
249
- *
250
- * Given the -z flag the new lines are separated by \0 character (left them as
251
- * new lines below for ease of reading)
252
- *
253
- * For modified, added, deleted, untracked:
254
- * 100644 100644 5716ca5 db3c77d M
255
- * file_one_path
256
- * :100644 100644 0835e4f 28096ea M
257
- * file_two_path
258
- * 1 0 file_one_path
259
- * 1 0 file_two_path
260
- *
261
- * For copied or renamed:
262
- * 100644 100644 5716ca5 db3c77d M
263
- * file_one_original_path
264
- * file_one_new_path
265
- * :100644 100644 0835e4f 28096ea M
266
- * file_two_original_path
267
- * file_two_new_path
268
- * 1 0
269
- * file_one_original_path
270
- * file_one_new_path
271
- * 1 0
272
- * file_two_original_path
273
- * file_two_new_path
274
- */
275
-
276
- export function parseRawLogWithNumstat(
277
- stdout: string,
278
- sha: string,
279
- parentCommitish: string
280
- ) {
281
- const files = new Array<CommittedFileChange>()
282
- let linesAdded = 0
283
- let linesDeleted = 0
284
- let numStatCount = 0
285
- const lines = stdout.split('\0')
286
-
287
- for (let i = 0; i < lines.length - 1; i++) {
288
- const line = lines[i]
289
- if (line.startsWith(':')) {
290
- const lineComponents = line.split(' ')
291
- const srcMode = forceUnwrap(
292
- 'Invalid log output (srcMode)',
293
- lineComponents[0]?.replace(':', '')
294
- )
295
- const dstMode = forceUnwrap(
296
- 'Invalid log output (dstMode)',
297
- lineComponents[1]
298
- )
299
- const status = forceUnwrap(
300
- 'Invalid log output (status)',
301
- lineComponents.at(-1)
302
- )
303
- const oldPath = /^R|C/.test(status)
304
- ? forceUnwrap('Missing old path', lines.at(++i))
305
- : undefined
306
-
307
- const path = forceUnwrap('Missing path', lines.at(++i))
308
-
309
- files.push(
310
- new CommittedFileChange(
311
- path,
312
- mapStatus(status, oldPath, srcMode, dstMode),
313
- sha,
314
- parentCommitish
315
- )
316
- )
317
- } else {
318
- const match = /^(\d+|-)\t(\d+|-)\t/.exec(line)
319
- const [, added, deleted] = forceUnwrap('Invalid numstat line', match)
320
- linesAdded += added === '-' ? 0 : parseInt(added, 10)
321
- linesDeleted += deleted === '-' ? 0 : parseInt(deleted, 10)
322
-
323
- // If this entry denotes a rename or copy the old and new paths are on
324
- // two separate fields (separated by \0). Otherwise they're on the same
325
- // line as the added and deleted lines.
326
- if (isCopyOrRename(files[numStatCount].status)) {
327
- i += 2
328
- }
329
- numStatCount++
330
- }
331
- }
332
-
333
- return { files, linesAdded, linesDeleted }
334
- }
335
-
336
- /** Get the commit for the given ref. */
337
- export async function getCommit(
338
- repository: Repository,
339
- ref: string
340
- ): Promise<Commit | null> {
341
- const commits = await getCommits(repository, ref, 1)
342
- if (commits.length < 1) {
343
- return null
344
- }
345
-
346
- return commits[0]
347
- }
348
-
349
- /** Get the author identity for the given shas */
350
- export async function getAuthors(repository: Repository, shas: string[]) {
351
- if (shas.length === 0) {
352
- return []
353
- }
354
-
355
- const { stdout } = await git(
356
- [
357
- 'log',
358
- '--format=format:%an <%ae> %ad',
359
- '--no-walk=unsorted',
360
- '--date=raw',
361
- '-z',
362
- '--stdin',
363
- ],
364
- repository.path,
365
- 'getAuthors',
366
- { stdin: shas.join('\n') }
367
- )
368
-
369
- const authors = stdout.split('\0').map(CommitIdentity.parseIdentity)
370
-
371
- // This can happen if there are duplicate shas in the input, git log will only
372
- // return the author once for each sha.
373
- assert.equal(authors.length, shas.length, 'Commit to author mismatch')
374
-
375
- return authors
376
- }
@@ -1,42 +0,0 @@
1
- import { Branch } from '../models/branch.js'
2
- import { ComputedAction } from '../models/computed-action.js'
3
- import { Repository } from '../models/repository.js'
4
- import { git, isGitError } from './core.js'
5
- import { GitError } from './exec.js'
6
-
7
- type MergeTreeResult =
8
- | { kind: ComputedAction.Clean }
9
- | { kind: ComputedAction.Conflicts; conflictedFiles: number }
10
- | { kind: ComputedAction.Invalid }
11
-
12
- export async function determineMergeability(
13
- repository: Repository,
14
- ours: Branch,
15
- theirs: Branch
16
- ) {
17
- return git(
18
- [
19
- 'merge-tree',
20
- '--write-tree',
21
- '--name-only',
22
- '--no-messages',
23
- '-z',
24
- ours.tip.sha,
25
- theirs.tip.sha,
26
- ],
27
- repository.path,
28
- 'determineMergeability',
29
- { successExitCodes: new Set([0, 1]) }
30
- )
31
- .then<MergeTreeResult>(({ stdout }) => {
32
- const conflictedFiles = (stdout.match(/\0/g)?.length ?? 0) - 1
33
- return conflictedFiles > 0
34
- ? { kind: ComputedAction.Conflicts, conflictedFiles }
35
- : { kind: ComputedAction.Clean }
36
- })
37
- .catch<MergeTreeResult>(e =>
38
- isGitError(e, GitError.CannotMergeUnrelatedHistories)
39
- ? Promise.resolve({ kind: ComputedAction.Invalid })
40
- : Promise.reject(e)
41
- )
42
- }
package/src/git/merge.ts DELETED
@@ -1,154 +0,0 @@
1
- import { join } from 'path'
2
- import { git, HookCallbackOptions } from './core.js'
3
- import { GitError } from './exec.js'
4
- import { Repository } from '../models/repository.js'
5
- import { pathExists } from '../lib/path-exists.js'
6
- import { createMultiOperationTerminalOutputCallback } from './multi-operation-terminal-output.js'
7
-
8
- export enum MergeResult {
9
- /** The merge completed successfully */
10
- Success,
11
- /**
12
- * The merge was a noop since the current branch
13
- * was already up to date with the target branch.
14
- */
15
- AlreadyUpToDate,
16
- /**
17
- * The merge failed, likely due to conflicts.
18
- */
19
- Failed,
20
- }
21
-
22
- export type MergeOptions = {
23
- /** Whether to perform a squash merge */
24
- readonly squash?: boolean
25
- /** Whether to bypass pre-merge and post-merge hooks */
26
- readonly noVerify?: boolean
27
- } & HookCallbackOptions
28
-
29
- /** Merge the named branch into the current branch. */
30
- export async function merge(
31
- repository: Repository,
32
- branch: string,
33
- options?: MergeOptions
34
- ): Promise<MergeResult> {
35
- const onTerminalOutputAvailable = options?.onTerminalOutputAvailable
36
- ? createMultiOperationTerminalOutputCallback(
37
- options?.onTerminalOutputAvailable
38
- )
39
- : undefined
40
-
41
- const args = ['merge']
42
-
43
- if (options?.squash) {
44
- args.push('--squash')
45
- }
46
-
47
- if (options?.noVerify) {
48
- args.push('--no-verify')
49
- }
50
-
51
- args.push(branch)
52
-
53
- const { exitCode, stdout } = await git(args, repository.path, 'merge', {
54
- expectedErrors: new Set([GitError.MergeConflicts]),
55
- interceptHooks: ['pre-merge-commit', 'post-merge', 'commit-msg'],
56
- onHookProgress: options?.onHookProgress,
57
- onHookFailure: options?.onHookFailure,
58
- onTerminalOutputAvailable,
59
- })
60
-
61
- if (exitCode !== 0) {
62
- return MergeResult.Failed
63
- }
64
-
65
- if (options?.squash) {
66
- const { exitCode } = await git(
67
- ['commit', '--no-edit'],
68
- repository.path,
69
- 'createSquashMergeCommit',
70
- {
71
- interceptHooks: [
72
- 'pre-merge-commit',
73
- 'prepare-commit-msg',
74
- 'commit-msg',
75
- 'post-commit',
76
- 'pre-auto-gc',
77
- ],
78
- onHookProgress: options?.onHookProgress,
79
- onHookFailure: options?.onHookFailure,
80
- onTerminalOutputAvailable,
81
- }
82
- )
83
- if (exitCode !== 0) {
84
- return MergeResult.Failed
85
- }
86
- }
87
-
88
- return stdout === noopMergeMessage
89
- ? MergeResult.AlreadyUpToDate
90
- : MergeResult.Success
91
- }
92
-
93
- const noopMergeMessage = 'Already up to date.\n'
94
-
95
- /**
96
- * Find the base commit between two commit-ish identifiers
97
- *
98
- * @returns the commit id of the merge base, or null if the two commit-ish
99
- * identifiers do not have a common base
100
- */
101
- export async function getMergeBase(
102
- repository: Repository,
103
- firstCommitish: string,
104
- secondCommitish: string
105
- ): Promise<string | null> {
106
- const process = await git(
107
- ['merge-base', firstCommitish, secondCommitish],
108
- repository.path,
109
- 'merge-base',
110
- {
111
- // - 1 is returned if a common ancestor cannot be resolved
112
- // - 128 is returned if a ref cannot be found
113
- // "warning: ignoring broken ref refs/remotes/origin/main."
114
- successExitCodes: new Set([0, 1, 128]),
115
- }
116
- )
117
-
118
- if (process.exitCode === 1 || process.exitCode === 128) {
119
- return null
120
- }
121
-
122
- return process.stdout.trim()
123
- }
124
-
125
- /**
126
- * Abort a mid-flight (conflicted) merge
127
- *
128
- * @param repository where to abort the merge
129
- */
130
- export async function abortMerge(repository: Repository): Promise<void> {
131
- await git(['merge', '--abort'], repository.path, 'abortMerge')
132
- }
133
-
134
- /**
135
- * Check the `.git/MERGE_HEAD` file exists in a repository to confirm
136
- * that it is in a conflicted state.
137
- */
138
- export async function isMergeHeadSet(repository: Repository): Promise<boolean> {
139
- const path = join(repository.resolvedGitDir, 'MERGE_HEAD')
140
- return await pathExists(path)
141
- }
142
-
143
- /**
144
- * Check the `.git/SQUASH_MSG` file exists in a repository
145
- * This would indicate we did a merge --squash and have not committed.. indicating
146
- * we have detected a conflict.
147
- *
148
- * Note: If we abort the merge, this doesn't get cleared automatically which
149
- * could lead to this being erroneously available in a non merge --squashing scenario.
150
- */
151
- export async function isSquashMsgSet(repository: Repository): Promise<boolean> {
152
- const path = join(repository.resolvedGitDir, 'SQUASH_MSG')
153
- return await pathExists(path)
154
- }
@@ -1,68 +0,0 @@
1
- import noop from '../lib/noop.js'
2
- import {
3
- TerminalOutput,
4
- TerminalOutputCallback,
5
- TerminalOutputListener,
6
- } from './core.js'
7
- import { pushTerminalChunk } from './push-terminal-chunk.js'
8
-
9
- /**
10
- * Creates a callback that aggregates terminal output from multiple Git
11
- * operations into a single stream.
12
- *
13
- * This function is useful when running multiple Git operations sequentially
14
- * where you want to present a unified terminal output view. It buffers output
15
- * from all operations and forwards them to upstream subscribers when requested.
16
- *
17
- * The callback maintains an internal buffer (default 256KB) and subscribes to
18
- * each Git operation's terminal output. When an upstream consumer requests the
19
- * output, it receives all previously buffered chunks followed by any new chunks
20
- * as they arrive.
21
- *
22
- * @param onTerminalOutputAvailable - The user provided callback which will
23
- * receive the aggregated terminal output.
24
- * @returns A callback that can be passed to individual Git operations as the
25
- * onTerminalOutputAvailable callback to capture their terminal output
26
- */
27
- export const createMultiOperationTerminalOutputCallback = (
28
- onTerminalOutputAvailable: TerminalOutputCallback,
29
- capacity = 256 * 1024
30
- ): TerminalOutputCallback => {
31
- let outputStarted = false
32
- const chunks: string[] = []
33
- const upstreamSubscribers = new Set<(chunk: TerminalOutput) => void>()
34
-
35
- const push = (chunk: string | Buffer) => {
36
- if (!outputStarted) {
37
- onTerminalOutputAvailable(function (cb) {
38
- upstreamSubscribers.add(cb)
39
- chunks.forEach(c => cb(c))
40
- return { unsubscribe: () => upstreamSubscribers.delete(cb) }
41
- })
42
- outputStarted = true
43
- }
44
-
45
- pushTerminalChunk(chunks, capacity, chunk)
46
- upstreamSubscribers.forEach(cb => cb(chunk))
47
- }
48
-
49
- // Called by each Git operation when terminal output is available. We'll
50
- // subscribe immediately to capture output from all operations and then
51
- // forward it to upstream callbacks if/when requested.
52
- const cb = function (subscribe: TerminalOutputListener) {
53
- subscribe(c => {
54
- if (Array.isArray(c)) {
55
- chunks.forEach(push)
56
- } else {
57
- push(c)
58
- }
59
- })
60
-
61
- // We can't unsubscribe because the user might request terminal output in
62
- // the future and we need to buffer the output from all operations to
63
- // ensure we can present the entire output.
64
- return { unsubscribe: noop }
65
- }
66
-
67
- return cb
68
- }