@hallaxius/forge 0.1.2 → 0.1.3

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/src/lib/git.ts CHANGED
@@ -1,6 +1,18 @@
1
- import simpleGit from "simple-git";
2
-
3
- const git = simpleGit();
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { diffLines } from "diff";
4
+ import git, {
5
+ currentBranch,
6
+ log as gitLog,
7
+ listBranches,
8
+ listRemotes,
9
+ listTags,
10
+ statusMatrix,
11
+ } from "isomorphic-git";
12
+ import http from "isomorphic-git/http/node";
13
+ import { resolveToken } from "./auth.js";
14
+
15
+ const dir = process.cwd();
4
16
 
5
17
  interface StatusResult {
6
18
  current: string;
@@ -29,354 +41,503 @@ interface StashEntry {
29
41
  description: string;
30
42
  }
31
43
 
44
+ function statusChar(head: number, workdir: number): string {
45
+ if (workdir === 0) return "D";
46
+ if (head === 0 && workdir === 2) return "?";
47
+ if (workdir === 2) return "M";
48
+ return " ";
49
+ }
50
+
51
+ function indexChar(head: number, stage: number): string {
52
+ if (head === 0 && stage === 2) return "A";
53
+ if (stage === 0 && head === 1) return "D";
54
+ if (stage === 2 && head === 1) return "M";
55
+ return " ";
56
+ }
57
+
32
58
  export async function getStatus(): Promise<StatusResult> {
33
- const status = await git.status();
34
- const log = await git.log({ maxCount: 5 });
59
+ const matrix = await statusMatrix({ fs, dir });
60
+
61
+ const current = (await currentBranch({ fs, dir, fullname: false })) || "";
62
+ const logResult = await gitLog({ fs, dir, depth: 5 });
63
+
64
+ const files = matrix
65
+ .filter(
66
+ ([_f, head, workdir, stage]) =>
67
+ head !== 1 || workdir !== 1 || stage !== 1,
68
+ )
69
+ .map(([filepath, head, workdir, stage]) => ({
70
+ path: filepath,
71
+ working_dir: statusChar(head as number, workdir as number),
72
+ index: indexChar(head as number, stage as number),
73
+ }));
35
74
 
36
75
  return {
37
- current: status.current || "",
38
- tracking: status.tracking || "",
39
- ahead: status.ahead,
40
- behind: status.behind,
41
- files: status.files.map((f) => ({
42
- path: f.path,
43
- working_dir: f.working_dir,
44
- index: f.index,
45
- })),
46
- recentCommits: log.all.map((c) => ({
47
- hash: c.hash,
48
- date: c.date,
49
- message: c.message,
76
+ current,
77
+ tracking: "",
78
+ ahead: 0,
79
+ behind: 0,
80
+ files,
81
+ recentCommits: logResult.map((c) => ({
82
+ hash: c.oid,
83
+ date: String(c.commit.author.timestamp),
84
+ message: c.commit.message,
50
85
  })),
51
86
  };
52
87
  }
53
88
 
54
89
  export async function commit(message: string): Promise<string> {
55
- const result = await git.commit(message);
56
- return result.commit || "";
90
+ const name =
91
+ (await git.getConfig({ fs, dir, path: "user.name" })) || "Unknown";
92
+ const email =
93
+ (await git.getConfig({ fs, dir, path: "user.email" })) ||
94
+ "unknown@localhost";
95
+
96
+ const result = await git.commit({
97
+ fs,
98
+ dir,
99
+ message,
100
+ author: { name, email },
101
+ });
102
+ return result;
103
+ }
104
+
105
+ export async function amendCommit(): Promise<void> {
106
+ const commits = await gitLog({ fs, dir, depth: 1 });
107
+ if (commits.length === 0) throw new Error("No commits to amend");
108
+ const { commit: c } = commits[0];
109
+
110
+ const name =
111
+ (await git.getConfig({ fs, dir, path: "user.name" })) || "Unknown";
112
+ const email =
113
+ (await git.getConfig({ fs, dir, path: "user.email" })) ||
114
+ "unknown@localhost";
115
+
116
+ await git.commit({
117
+ fs,
118
+ dir,
119
+ message: c.message,
120
+ author: c.author,
121
+ committer: { name, email },
122
+ tree: c.tree,
123
+ parent: c.parent.map((p) => p.toString()),
124
+ });
125
+ }
126
+
127
+ export async function add(filepaths: string | string[]): Promise<void> {
128
+ const files = Array.isArray(filepaths) ? filepaths : [filepaths];
129
+ for (const filepath of files) {
130
+ await git.add({ fs, dir, filepath });
131
+ }
57
132
  }
58
133
 
59
134
  export async function push(force: boolean = false): Promise<string> {
60
- const args = force ? (["-f"] as any) : undefined;
61
- const result = await git.push("origin", undefined as any, args);
135
+ const token = await resolveToken();
136
+ const result = await git.push({
137
+ fs,
138
+ http,
139
+ dir,
140
+ force,
141
+ token,
142
+ oauth2format: "github",
143
+ });
62
144
  return result;
63
145
  }
64
146
 
65
147
  export async function pullRebase(): Promise<string> {
66
- const result = await git.pull(["--rebase"]);
148
+ const token = await resolveToken();
149
+ await git.fetch({ fs, http, dir, token, oauth2format: "github" });
150
+ const current = (await currentBranch({ fs, dir })) || "";
151
+ const result = await git.merge({
152
+ fs,
153
+ dir,
154
+ theirs: current,
155
+ fastForwardOnly: true,
156
+ });
67
157
  return result;
68
158
  }
69
159
 
70
160
  export async function log(maxCount: number = 10): Promise<LogEntry[]> {
71
- const result = await git.log({ maxCount });
72
- return result.all.map((c) => ({
73
- hash: c.hash,
74
- date: c.date,
75
- message: c.message,
76
- author: c.author_name,
161
+ const result = await gitLog({ fs, dir, depth: maxCount, ref: "HEAD" });
162
+ return result.map((c) => ({
163
+ hash: c.oid,
164
+ date: String(c.commit.author.timestamp),
165
+ message: c.commit.message,
166
+ author: c.commit.author.name,
77
167
  }));
78
168
  }
79
169
 
80
170
  export async function diff(): Promise<string> {
81
- const result = await git.diff();
82
- return result;
171
+ const matrix = await statusMatrix({ fs, dir });
172
+ const changed = matrix.filter(
173
+ ([_f, head, workdir, _stage]) => head !== 1 || workdir !== 1,
174
+ );
175
+ if (changed.length === 0) return "";
176
+
177
+ const headOid = await git.resolveRef({ fs, dir, ref: "HEAD" });
178
+ const output: string[] = [];
179
+
180
+ for (const [filepath, head, workdir] of changed) {
181
+ let oldContent = "";
182
+ let newContent = "";
183
+
184
+ if ((head as number) !== 0) {
185
+ try {
186
+ const blob = await git.readBlob({
187
+ fs,
188
+ dir,
189
+ oid: headOid,
190
+ filepath,
191
+ });
192
+ oldContent = new TextDecoder().decode(blob.blob);
193
+ } catch {}
194
+ }
195
+
196
+ if ((workdir as number) !== 0) {
197
+ try {
198
+ newContent = readFileSync(join(dir, filepath), "utf-8");
199
+ } catch {}
200
+ }
201
+
202
+ output.push(`diff --git a/${filepath} b/${filepath}`);
203
+ const patch = diffLines(oldContent, newContent);
204
+ for (const part of patch) {
205
+ if (part.added) {
206
+ for (const line of part.value.split("\n").filter(Boolean)) {
207
+ output.push(`+${line}`);
208
+ }
209
+ } else if (part.removed) {
210
+ for (const line of part.value.split("\n").filter(Boolean)) {
211
+ output.push(`-${line}`);
212
+ }
213
+ } else {
214
+ for (const line of part.value.split("\n").filter(Boolean)) {
215
+ output.push(` ${line}`);
216
+ }
217
+ }
218
+ }
219
+ }
220
+
221
+ return output.join("\n");
83
222
  }
84
223
 
85
224
  export async function diffStaged(): Promise<string> {
86
- const result = await git.diff(["--cached"]);
87
- return result;
225
+ const matrix = await statusMatrix({ fs, dir });
226
+ const changed = matrix.filter(
227
+ ([_f, head, _workdir, stage]) => head !== 1 || (stage as number) !== 1,
228
+ );
229
+ if (changed.length === 0) return "";
230
+
231
+ const headOid = await git.resolveRef({ fs, dir, ref: "HEAD" });
232
+ const output: string[] = [];
233
+
234
+ for (const [filepath, head, _workdir, stage] of changed) {
235
+ let oldContent = "";
236
+ let newContent = "";
237
+
238
+ if ((head as number) !== 0) {
239
+ try {
240
+ const blob = await git.readBlob({
241
+ fs,
242
+ dir,
243
+ oid: headOid,
244
+ filepath,
245
+ });
246
+ oldContent = new TextDecoder().decode(blob.blob);
247
+ } catch {}
248
+ }
249
+
250
+ if ((stage as number) !== 0) {
251
+ try {
252
+ const blob = await git.readBlob({
253
+ fs,
254
+ dir,
255
+ oid: headOid,
256
+ filepath,
257
+ });
258
+ newContent = new TextDecoder().decode(blob.blob);
259
+ } catch {}
260
+ }
261
+
262
+ output.push(`diff --git a/${filepath} b/${filepath} (staged)`);
263
+ const patch = diffLines(oldContent, newContent);
264
+ for (const part of patch) {
265
+ if (part.added) {
266
+ for (const line of part.value.split("\n").filter(Boolean)) {
267
+ output.push(`+${line}`);
268
+ }
269
+ } else if (part.removed) {
270
+ for (const line of part.value.split("\n").filter(Boolean)) {
271
+ output.push(`-${line}`);
272
+ }
273
+ } else {
274
+ for (const line of part.value.split("\n").filter(Boolean)) {
275
+ output.push(` ${line}`);
276
+ }
277
+ }
278
+ }
279
+ }
280
+
281
+ return output.join("\n");
88
282
  }
89
283
 
90
284
  export async function getBranches(): Promise<BranchesResult> {
91
- const result = await git.branch();
285
+ const all = await listBranches({ fs, dir });
286
+ const current = (await currentBranch({ fs, dir, fullname: false })) || "";
92
287
  return {
93
- current: result.current,
94
- branches: result.branches
95
- ? Object.keys(result.branches).filter((b) => b !== result.current)
96
- : [],
97
- all: result.all || [],
288
+ current,
289
+ branches: all.filter((b) => b !== current),
290
+ all,
98
291
  };
99
292
  }
100
293
 
101
294
  export async function createBranch(name: string): Promise<void> {
102
- await git.branch([name]);
295
+ await git.branch({ fs, dir, ref: name });
103
296
  }
104
297
 
105
298
  export async function deleteBranch(
106
299
  name: string,
107
300
  force: boolean = false,
108
301
  ): Promise<void> {
109
- const args = force ? ["-D", name] : ["-d", name];
110
- await git.branch(args);
302
+ if (force) {
303
+ await git.deleteBranch({ fs, dir, ref: name });
304
+ } else {
305
+ await git.deleteBranch({ fs, dir, ref: name });
306
+ }
111
307
  }
112
308
 
113
309
  export async function switchBranch(name: string): Promise<void> {
114
- await git.checkout(name);
310
+ await git.checkout({ fs, dir, ref: name });
115
311
  }
116
312
 
117
313
  export async function stash(): Promise<string> {
118
- const result = await git.stash();
119
- return result;
314
+ await git.stash({ fs, dir });
315
+ return "Stash saved";
120
316
  }
121
317
 
122
318
  export async function stashPop(): Promise<string> {
123
- const result = await git.stash(["pop"]);
124
- return result;
319
+ const stashes = await stashList();
320
+ if (stashes.length === 0) throw new Error("No stashes to pop");
321
+
322
+ try {
323
+ await git.stash({ fs, dir });
324
+ } catch {
325
+ throw new Error("Failed to apply stash");
326
+ }
327
+
328
+ const refs = await git.listRefs({ fs, dir, prefix: "refs/stash" });
329
+ if (refs.length > 0) {
330
+ await git.deleteRef({ fs, dir, ref: refs[0] });
331
+ }
332
+
333
+ return "Stash popped";
125
334
  }
126
335
 
127
336
  export async function stashList(): Promise<StashEntry[]> {
128
- const result = await git.stashList();
129
- return result.all.map((s, i) => ({
130
- index: i + 1,
131
- description: s.message,
132
- }));
337
+ try {
338
+ const stashLog = await gitLog({ fs, dir, ref: "refs/stash" });
339
+ return stashLog.map((c, i) => ({
340
+ index: i + 1,
341
+ description: c.commit.message,
342
+ }));
343
+ } catch {
344
+ return [];
345
+ }
133
346
  }
134
347
 
135
348
  export async function tag(name: string, message?: string): Promise<string> {
136
349
  if (message) {
137
- await git.tag(["-a", name, "-m", message]);
350
+ await git.tag({ fs, dir, ref: name, message });
138
351
  } else {
139
- await git.tag([name]);
352
+ await git.tag({ fs, dir, ref: name });
140
353
  }
141
354
  return name;
142
355
  }
143
356
 
144
357
  export async function tagList(): Promise<string[]> {
145
- const result = await git.tag();
146
- return result.split("\n").filter(Boolean);
358
+ return listTags({ fs, dir });
147
359
  }
148
360
 
149
361
  export async function fetch(): Promise<string> {
150
- const result = await git.fetch();
362
+ const token = await resolveToken();
363
+ const result = await git.fetch({
364
+ fs,
365
+ http,
366
+ dir,
367
+ token,
368
+ oauth2format: "github",
369
+ });
151
370
  return result;
152
371
  }
153
372
 
154
373
  export async function undo(): Promise<string> {
155
- const result = await git.reset(["--soft", "HEAD~1"]);
156
- return result;
374
+ const commits = await gitLog({ fs, dir, depth: 1, ref: "HEAD" });
375
+ if (commits.length === 0) throw new Error("No commits to undo");
376
+ const c = commits[0];
377
+ if (c.commit.parent.length === 0) throw new Error("Cannot undo root commit");
378
+
379
+ const parentOid = c.commit.parent[0];
380
+ await git.writeRef({
381
+ fs,
382
+ dir,
383
+ ref: "HEAD",
384
+ value: parentOid.toString(),
385
+ force: true,
386
+ });
387
+ return `Undone to ${parentOid.toString().slice(0, 7)}`;
157
388
  }
158
389
 
159
390
  export async function getCurrentBranch(): Promise<string> {
160
- const result = await git.branch();
161
- return result.current;
391
+ return (await currentBranch({ fs, dir })) || "";
162
392
  }
163
393
 
164
394
  export async function clone(
165
395
  url: string,
166
- dir?: string,
396
+ targetDir?: string,
167
397
  options?: {
168
- ssh?: boolean;
169
398
  depth?: number;
170
399
  branch?: string;
171
400
  recurseSubmodules?: boolean;
172
401
  },
173
402
  ): Promise<string> {
174
- const args: string[] = [];
175
- if (options?.depth) args.push("--depth", String(options.depth));
176
- if (options?.branch) args.push("--branch", options.branch);
177
- if (options?.recurseSubmodules) args.push("--recurse-submodules");
178
- const targetDir = dir || url.split("/").pop()?.replace(".git", "") || "repo";
179
- await git.clone(url, targetDir, args);
180
- return targetDir;
403
+ const token = await resolveToken();
404
+ const cloneDir =
405
+ targetDir || url.split("/").pop()?.replace(".git", "") || "repo";
406
+
407
+ await git.clone({
408
+ fs,
409
+ http,
410
+ dir: cloneDir,
411
+ url,
412
+ singleBranch: !!options?.branch,
413
+ ref: options?.branch,
414
+ depth: options?.depth,
415
+ token,
416
+ oauth2format: "github",
417
+ });
418
+
419
+ return cloneDir;
181
420
  }
182
421
 
183
422
  export async function init(
184
- dir?: string,
423
+ targetDir?: string,
185
424
  options?: { initialBranch?: string },
186
425
  ): Promise<void> {
187
- const opts: string[] = [];
188
- if (options?.initialBranch)
189
- opts.push("--initial-branch", options.initialBranch);
190
- if (dir) opts.push(dir);
191
- await git.init(opts.length > 0 ? opts : (true as any));
192
- }
193
-
194
- interface RemoteEntry {
195
- name: string;
196
- url: string;
426
+ const initDir = targetDir || ".";
427
+ await git.init({
428
+ fs,
429
+ dir: initDir,
430
+ defaultBranch: options?.initialBranch,
431
+ });
197
432
  }
198
433
 
199
434
  export async function remoteAdd(name: string, url: string): Promise<void> {
200
- await git.addRemote(name, url);
435
+ await git.addRemote({ fs, dir, remote: name, url });
201
436
  }
202
437
 
203
438
  export async function remoteRemove(name: string): Promise<void> {
204
- await git.removeRemote(name);
439
+ await git.deleteRemote({ fs, dir, remote: name });
205
440
  }
206
441
 
207
442
  export async function remoteSetUrl(
208
443
  name: string,
209
444
  newUrl: string,
210
445
  ): Promise<void> {
211
- await git.raw(["remote", "set-url", name, newUrl]);
446
+ await git.setConfig({
447
+ fs,
448
+ dir,
449
+ path: `remote.${name}.url`,
450
+ value: newUrl,
451
+ });
212
452
  }
213
453
 
214
454
  export async function remoteRename(
215
455
  oldName: string,
216
456
  newName: string,
217
457
  ): Promise<void> {
218
- await git.raw(["remote", "rename", oldName, newName]);
219
- }
220
-
221
- export async function remoteGetUrl(name: string): Promise<string> {
222
- const result = await git.raw(["remote", "get-url", name]);
223
- return result.trim();
224
- }
458
+ const url = await git.getConfig({
459
+ fs,
460
+ dir,
461
+ path: `remote.${oldName}.url`,
462
+ });
463
+ if (!url) throw new Error(`Remote '${oldName}' not found`);
225
464
 
226
- export async function remoteList(): Promise<RemoteEntry[]> {
227
- const result = await git.getRemotes(true);
228
- return result.map((r) => ({ name: r.name, url: r.refs.fetch }));
465
+ await remoteAdd(newName, url);
466
+ await remoteRemove(oldName);
229
467
  }
230
468
 
231
- interface WorktreeEntry {
232
- path: string;
233
- branch: string;
234
- hash: string;
235
- }
236
-
237
- export async function worktreeAdd(
238
- path: string,
239
- branch?: string,
240
- options?: { new?: boolean; detach?: boolean },
241
- ): Promise<void> {
242
- const args = ["worktree", "add"];
243
- if (options?.detach) args.push("--detach");
244
- args.push(path);
245
- if (branch) {
246
- if (options?.new) args.push(branch);
247
- else args.push(branch);
248
- }
249
- await git.raw(args);
250
- }
251
-
252
- export async function worktreeList(): Promise<WorktreeEntry[]> {
253
- const result = await git.raw(["worktree", "list", "--porcelain"]);
254
- const entries: WorktreeEntry[] = [];
255
- const lines = result.split("\n");
256
- let current: Partial<WorktreeEntry> = {};
257
- for (const line of lines) {
258
- if (line.startsWith("worktree ")) {
259
- current.path = line.slice(9).trim();
260
- } else if (line.startsWith("HEAD ")) {
261
- current.hash = line.slice(5).trim();
262
- } else if (line.startsWith("branch ")) {
263
- current.branch = line.slice(7).trim().replace("refs/heads/", "");
264
- } else if (line === "") {
265
- if (current.path) entries.push(current as WorktreeEntry);
266
- current = {};
267
- }
268
- }
269
- if (current.path) entries.push(current as WorktreeEntry);
270
- return entries;
271
- }
272
-
273
- export async function worktreeRemove(
274
- path: string,
275
- force: boolean = false,
276
- ): Promise<void> {
277
- const args = ["worktree", "remove"];
278
- if (force) args.push("--force");
279
- args.push(path);
280
- await git.raw(args);
469
+ export async function remoteGetUrl(name: string): Promise<string> {
470
+ const url = await git.getConfig({
471
+ fs,
472
+ dir,
473
+ path: `remote.${name}.url`,
474
+ });
475
+ if (!url) throw new Error(`Remote '${name}' not found`);
476
+ return url;
281
477
  }
282
478
 
283
- export async function worktreePrune(
284
- dryRun: boolean = false,
285
- ): Promise<string[]> {
286
- const args = ["worktree", "prune"];
287
- if (dryRun) args.push("--dry-run");
288
- const result = await git.raw(args);
289
- return result.split("\n").filter(Boolean);
479
+ export async function remoteList(): Promise<{ name: string; url: string }[]> {
480
+ const remotes = await listRemotes({ fs, dir });
481
+ return remotes.map((r) => ({ name: r.remote, url: r.url }));
290
482
  }
291
483
 
292
484
  export async function merge(
293
485
  branch: string,
294
- options?: { noFF?: boolean; squash?: boolean; noCommit?: boolean },
295
- ): Promise<string> {
296
- const args = ["merge"];
297
- if (options?.noFF) args.push("--no-ff");
298
- if (options?.squash) args.push("--squash");
299
- if (options?.noCommit) args.push("--no-commit");
300
- args.push(branch);
301
- const result = await git.raw(args);
302
- return result;
303
- }
304
-
305
- export async function cherryPick(
306
- commits: string[],
307
- options?: { noCommit?: boolean; mainline?: number },
308
- ): Promise<void> {
309
- const args = ["cherry-pick"];
310
- if (options?.noCommit) args.push("--no-commit");
311
- if (options?.mainline) args.push("-m", String(options.mainline));
312
- args.push(...commits);
313
- await git.raw(args);
314
- }
315
-
316
- export async function cherryPickContinue(): Promise<void> {
317
- await git.raw(["cherry-pick", "--continue"]);
318
- }
319
-
320
- export async function cherryPickAbort(): Promise<void> {
321
- await git.raw(["cherry-pick", "--abort"]);
322
- }
323
-
324
- export async function clean(options?: {
325
- dryRun?: boolean;
326
- force?: boolean;
327
- exclude?: string;
328
- }): Promise<string[]> {
329
- const args = ["clean", "-d"];
330
- if (options?.dryRun) args.push("-n");
331
- if (options?.force) args.push("-f");
332
- else args.push("-f");
333
- if (options?.exclude) args.push("-x", options.exclude);
334
- const result = await git.raw(args);
335
- return result.split("\n").filter(Boolean);
336
- }
337
-
338
- export async function archive(
339
- format: string,
340
- options?: { prefix?: string; output?: string; treeIsh?: string },
486
+ options?: {
487
+ noFF?: boolean;
488
+ squash?: boolean;
489
+ noCommit?: boolean;
490
+ },
341
491
  ): Promise<string> {
342
- const args = ["archive", `--format=${format}`];
343
- if (options?.prefix) args.push(`--prefix=${options.prefix}`);
344
- if (options?.output) args.push(`--output=${options.output}`);
345
- if (options?.treeIsh) args.push(options.treeIsh);
346
- else args.push("HEAD");
347
- const result = await git.raw(args);
492
+ const name =
493
+ (await git.getConfig({ fs, dir, path: "user.name" })) || "Unknown";
494
+ const email =
495
+ (await git.getConfig({ fs, dir, path: "user.email" })) ||
496
+ "unknown@localhost";
497
+
498
+ const result = await git.merge({
499
+ fs,
500
+ dir,
501
+ theirs: branch,
502
+ ours: undefined,
503
+ noCommit: options?.noCommit,
504
+ squash: options?.squash,
505
+ fastForward: !options?.noFF,
506
+ author: { name, email },
507
+ committer: { name, email },
508
+ });
348
509
  return result;
349
510
  }
350
511
 
351
- export async function bisectStart(
352
- bad?: string,
353
- good?: string[],
354
- ): Promise<void> {
355
- await git.raw(["bisect", "start"]);
356
- if (bad) await git.raw(["bisect", "bad", bad]);
357
- if (good && good.length > 0) {
358
- for (const g of good) await git.raw(["bisect", "good", g]);
359
- }
360
- }
361
-
362
- export async function bisectBad(commit?: string): Promise<void> {
363
- const args = ["bisect", "bad"];
364
- if (commit) args.push(commit);
365
- await git.raw(args);
366
- }
367
-
368
- export async function bisectGood(commits: string[]): Promise<void> {
369
- for (const c of commits) await git.raw(["bisect", "good", c]);
370
- }
371
-
372
- export async function bisectReset(): Promise<void> {
373
- await git.raw(["bisect", "reset"]);
374
- }
375
-
376
- export async function bisectLog(): Promise<string> {
377
- return await git.raw(["bisect", "log"]);
378
- }
379
-
380
- export async function bisectRun(cmd: string): Promise<void> {
381
- await git.raw(["bisect", "run", cmd]);
382
- }
512
+ export default {
513
+ getStatus,
514
+ commit,
515
+ amendCommit,
516
+ add,
517
+ push,
518
+ pullRebase,
519
+ log,
520
+ diff,
521
+ diffStaged,
522
+ getBranches,
523
+ createBranch,
524
+ deleteBranch,
525
+ switchBranch,
526
+ stash,
527
+ stashPop,
528
+ stashList,
529
+ tag,
530
+ tagList,
531
+ fetch,
532
+ undo,
533
+ getCurrentBranch,
534
+ clone,
535
+ init,
536
+ remoteAdd,
537
+ remoteRemove,
538
+ remoteSetUrl,
539
+ remoteRename,
540
+ remoteGetUrl,
541
+ remoteList,
542
+ merge,
543
+ };