@zjex/git-workflow 0.4.3 → 0.4.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.
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ var __export = (target, all) => {
10
10
  };
11
11
 
12
12
  // src/utils.ts
13
- import { execSync } from "child_process";
13
+ import { execSync, spawn } from "child_process";
14
14
  function exec(cmd, silent = false) {
15
15
  try {
16
16
  const options = {
@@ -51,6 +51,37 @@ function getMainBranch() {
51
51
  function divider() {
52
52
  console.log(colors.dim("\u2500".repeat(40)));
53
53
  }
54
+ function execAsync(command, spinner) {
55
+ return new Promise((resolve) => {
56
+ const [cmd, ...args] = command.split(" ");
57
+ const process2 = spawn(cmd, args, {
58
+ stdio: spinner ? "pipe" : "inherit"
59
+ });
60
+ process2.on("close", (code) => {
61
+ resolve(code === 0);
62
+ });
63
+ process2.on("error", () => {
64
+ resolve(false);
65
+ });
66
+ });
67
+ }
68
+ async function execWithSpinner(command, spinner, successMessage, errorMessage) {
69
+ const success = await execAsync(command, spinner);
70
+ if (success) {
71
+ if (successMessage) {
72
+ spinner.succeed(successMessage);
73
+ } else {
74
+ spinner.succeed();
75
+ }
76
+ } else {
77
+ if (errorMessage) {
78
+ spinner.fail(errorMessage);
79
+ } else {
80
+ spinner.fail();
81
+ }
82
+ }
83
+ return success;
84
+ }
54
85
  var colors, TODAY, theme;
55
86
  var init_utils = __esm({
56
87
  "src/utils.ts"() {
@@ -90,7 +121,7 @@ __export(update_notifier_exports, {
90
121
  checkForUpdates: () => checkForUpdates,
91
122
  clearUpdateCache: () => clearUpdateCache
92
123
  });
93
- import { execSync as execSync6 } from "child_process";
124
+ import { execSync as execSync3 } from "child_process";
94
125
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, existsSync as existsSync3, unlinkSync as unlinkSync2 } from "fs";
95
126
  import { homedir as homedir3 } from "os";
96
127
  import { join as join4 } from "path";
@@ -154,7 +185,7 @@ function backgroundCheck(currentVersion, packageName) {
154
185
  }
155
186
  function isUsingVolta() {
156
187
  try {
157
- const whichGw = execSync6("which gw", { encoding: "utf-8" }).trim();
188
+ const whichGw = execSync3("which gw", { encoding: "utf-8" }).trim();
158
189
  return whichGw.includes(".volta");
159
190
  } catch {
160
191
  return false;
@@ -162,7 +193,7 @@ function isUsingVolta() {
162
193
  }
163
194
  async function getLatestVersion(packageName) {
164
195
  try {
165
- const result = execSync6(`npm view ${packageName} version`, {
196
+ const result = execSync3(`npm view ${packageName} version`, {
166
197
  encoding: "utf-8",
167
198
  timeout: 3e3,
168
199
  stdio: ["pipe", "pipe", "ignore"]
@@ -244,7 +275,7 @@ async function performUpdate(packageName) {
244
275
  spinner: "dots"
245
276
  }).start();
246
277
  try {
247
- execSync6(updateCommand, {
278
+ execSync3(updateCommand, {
248
279
  encoding: "utf-8",
249
280
  stdio: ["pipe", "pipe", "pipe"]
250
281
  });
@@ -327,7 +358,6 @@ import { ExitPromptError } from "@inquirer/core";
327
358
 
328
359
  // src/commands/branch.ts
329
360
  init_utils();
330
- import { execSync as execSync2 } from "child_process";
331
361
  import { select, input } from "@inquirer/prompts";
332
362
  import ora from "ora";
333
363
 
@@ -511,12 +541,15 @@ async function createBranch(type, baseBranchArg) {
511
541
  }
512
542
  if (shouldPush) {
513
543
  const pushSpinner = ora("\u6B63\u5728\u63A8\u9001\u5230\u8FDC\u7A0B...").start();
514
- try {
515
- execSync2(`git push -u origin "${branchName}"`, { stdio: "pipe" });
516
- pushSpinner.succeed(`\u5DF2\u63A8\u9001\u5230\u8FDC\u7A0B: origin/${branchName}`);
517
- } catch {
518
- pushSpinner.warn(
519
- "\u8FDC\u7A0B\u63A8\u9001\u5931\u8D25\uFF0C\u53EF\u7A0D\u540E\u624B\u52A8\u6267\u884C: git push -u origin " + branchName
544
+ const success = await execWithSpinner(
545
+ `git push -u origin "${branchName}"`,
546
+ pushSpinner,
547
+ `\u5DF2\u63A8\u9001\u5230\u8FDC\u7A0B: origin/${branchName}`,
548
+ "\u8FDC\u7A0B\u63A8\u9001\u5931\u8D25"
549
+ );
550
+ if (!success) {
551
+ console.log(
552
+ colors.dim(` \u53EF\u7A0D\u540E\u624B\u52A8\u6267\u884C: git push -u origin ${branchName}`)
520
553
  );
521
554
  }
522
555
  }
@@ -586,14 +619,12 @@ async function deleteBranch(branchArg) {
586
619
  return;
587
620
  }
588
621
  const spinner = ora(`\u6B63\u5728\u5220\u9664\u8FDC\u7A0B\u5206\u652F: origin/${remoteBranch}`).start();
589
- try {
590
- execSync2(`git push origin --delete "${remoteBranch}"`, {
591
- stdio: "pipe"
592
- });
593
- spinner.succeed(`\u8FDC\u7A0B\u5206\u652F\u5DF2\u5220\u9664: origin/${remoteBranch}`);
594
- } catch {
595
- spinner.fail("\u8FDC\u7A0B\u5206\u652F\u5220\u9664\u5931\u8D25");
596
- }
622
+ await execWithSpinner(
623
+ `git push origin --delete "${remoteBranch}"`,
624
+ spinner,
625
+ `\u8FDC\u7A0B\u5206\u652F\u5DF2\u5220\u9664: origin/${remoteBranch}`,
626
+ "\u8FDC\u7A0B\u5206\u652F\u5220\u9664\u5931\u8D25"
627
+ );
597
628
  return;
598
629
  }
599
630
  }
@@ -618,12 +649,12 @@ async function deleteBranch(branchArg) {
618
649
  });
619
650
  if (deleteRemote) {
620
651
  const spinner = ora(`\u6B63\u5728\u5220\u9664\u8FDC\u7A0B\u5206\u652F: origin/${branch}`).start();
621
- try {
622
- execSync2(`git push origin --delete "${branch}"`, { stdio: "pipe" });
623
- spinner.succeed(`\u8FDC\u7A0B\u5206\u652F\u5DF2\u5220\u9664: origin/${branch}`);
624
- } catch {
625
- spinner.fail("\u8FDC\u7A0B\u5206\u652F\u5220\u9664\u5931\u8D25");
626
- }
652
+ await execWithSpinner(
653
+ `git push origin --delete "${branch}"`,
654
+ spinner,
655
+ `\u8FDC\u7A0B\u5206\u652F\u5DF2\u5220\u9664: origin/${branch}`,
656
+ "\u8FDC\u7A0B\u5206\u652F\u5220\u9664\u5931\u8D25"
657
+ );
627
658
  }
628
659
  } else {
629
660
  console.log(colors.red(`\u5206\u652F\u4E0D\u5B58\u5728: ${branch}`));
@@ -643,27 +674,28 @@ async function deleteBranch(branchArg) {
643
674
  return;
644
675
  }
645
676
  const localSpinner = ora(`\u6B63\u5728\u5220\u9664\u672C\u5730\u5206\u652F: ${branch}`).start();
646
- try {
647
- execSync2(`git branch -D "${branch}"`, { stdio: "pipe" });
648
- localSpinner.succeed(`\u672C\u5730\u5206\u652F\u5DF2\u5220\u9664: ${branch}`);
649
- } catch {
650
- localSpinner.fail("\u672C\u5730\u5206\u652F\u5220\u9664\u5931\u8D25");
677
+ const localSuccess = await execWithSpinner(
678
+ `git branch -D "${branch}"`,
679
+ localSpinner,
680
+ `\u672C\u5730\u5206\u652F\u5DF2\u5220\u9664: ${branch}`,
681
+ "\u672C\u5730\u5206\u652F\u5220\u9664\u5931\u8D25"
682
+ );
683
+ if (!localSuccess) {
651
684
  return;
652
685
  }
653
686
  if (hasRemote) {
654
687
  const remoteSpinner = ora(`\u6B63\u5728\u5220\u9664\u8FDC\u7A0B\u5206\u652F: origin/${branch}`).start();
655
- try {
656
- execSync2(`git push origin --delete "${branch}"`, { stdio: "pipe" });
657
- remoteSpinner.succeed(`\u8FDC\u7A0B\u5206\u652F\u5DF2\u5220\u9664: origin/${branch}`);
658
- } catch {
659
- remoteSpinner.fail("\u8FDC\u7A0B\u5206\u652F\u5220\u9664\u5931\u8D25");
660
- }
688
+ await execWithSpinner(
689
+ `git push origin --delete "${branch}"`,
690
+ remoteSpinner,
691
+ `\u8FDC\u7A0B\u5206\u652F\u5DF2\u5220\u9664: origin/${branch}`,
692
+ "\u8FDC\u7A0B\u5206\u652F\u5220\u9664\u5931\u8D25"
693
+ );
661
694
  }
662
695
  }
663
696
 
664
697
  // src/commands/tag.ts
665
698
  init_utils();
666
- import { execSync as execSync3 } from "child_process";
667
699
  import { select as select2, input as input2 } from "@inquirer/prompts";
668
700
  import ora2 from "ora";
669
701
  async function listTags(prefix) {
@@ -970,28 +1002,29 @@ async function createTag(inputPrefix) {
970
1002
  console.log(colors.yellow("\u5DF2\u53D6\u6D88"));
971
1003
  return;
972
1004
  }
973
- doCreateTag(nextTag);
1005
+ await doCreateTag(nextTag);
974
1006
  }
975
- function doCreateTag(tagName) {
1007
+ async function doCreateTag(tagName) {
976
1008
  divider();
977
1009
  const spinner = ora2(`\u6B63\u5728\u521B\u5EFA tag: ${tagName}`).start();
978
- try {
979
- execSync3(`git tag -a "${tagName}" -m "Release ${tagName}"`, {
980
- stdio: "pipe"
981
- });
982
- spinner.succeed(`Tag \u521B\u5EFA\u6210\u529F: ${tagName}`);
983
- } catch {
984
- spinner.fail("tag \u521B\u5EFA\u5931\u8D25");
1010
+ const success = await execWithSpinner(
1011
+ `git tag -a "${tagName}" -m "Release ${tagName}"`,
1012
+ spinner,
1013
+ `Tag \u521B\u5EFA\u6210\u529F: ${tagName}`,
1014
+ "tag \u521B\u5EFA\u5931\u8D25"
1015
+ );
1016
+ if (!success) {
985
1017
  return;
986
1018
  }
987
1019
  const pushSpinner = ora2("\u6B63\u5728\u63A8\u9001\u5230\u8FDC\u7A0B...").start();
988
- try {
989
- execSync3(`git push origin "${tagName}"`, { stdio: "pipe" });
990
- pushSpinner.succeed(`Tag \u5DF2\u63A8\u9001: ${tagName}`);
991
- } catch {
992
- pushSpinner.warn(
993
- `\u8FDC\u7A0B\u63A8\u9001\u5931\u8D25\uFF0C\u53EF\u7A0D\u540E\u624B\u52A8\u6267\u884C: git push origin ${tagName}`
994
- );
1020
+ const pushSuccess = await execWithSpinner(
1021
+ `git push origin "${tagName}"`,
1022
+ pushSpinner,
1023
+ `Tag \u5DF2\u63A8\u9001: ${tagName}`,
1024
+ "\u8FDC\u7A0B\u63A8\u9001\u5931\u8D25"
1025
+ );
1026
+ if (!pushSuccess) {
1027
+ console.log(colors.dim(` \u53EF\u7A0D\u540E\u624B\u52A8\u6267\u884C: git push origin ${tagName}`));
995
1028
  }
996
1029
  }
997
1030
  async function deleteTag() {
@@ -1029,11 +1062,13 @@ async function deleteTag() {
1029
1062
  }
1030
1063
  divider();
1031
1064
  const spinner = ora2(`\u6B63\u5728\u5220\u9664\u672C\u5730 tag: ${tagToDelete}`).start();
1032
- try {
1033
- execSync3(`git tag -d "${tagToDelete}"`, { stdio: "pipe" });
1034
- spinner.succeed(`\u672C\u5730 tag \u5DF2\u5220\u9664: ${tagToDelete}`);
1035
- } catch {
1036
- spinner.fail("\u672C\u5730 tag \u5220\u9664\u5931\u8D25");
1065
+ const localSuccess = await execWithSpinner(
1066
+ `git tag -d "${tagToDelete}"`,
1067
+ spinner,
1068
+ `\u672C\u5730 tag \u5DF2\u5220\u9664: ${tagToDelete}`,
1069
+ "\u672C\u5730 tag \u5220\u9664\u5931\u8D25"
1070
+ );
1071
+ if (!localSuccess) {
1037
1072
  return;
1038
1073
  }
1039
1074
  const deleteRemote = await select2({
@@ -1046,10 +1081,12 @@ async function deleteTag() {
1046
1081
  });
1047
1082
  if (deleteRemote) {
1048
1083
  const pushSpinner = ora2("\u6B63\u5728\u5220\u9664\u8FDC\u7A0B tag...").start();
1049
- try {
1050
- execSync3(`git push origin --delete "${tagToDelete}"`, { stdio: "pipe" });
1051
- pushSpinner.succeed(`\u8FDC\u7A0B tag \u5DF2\u5220\u9664: ${tagToDelete}`);
1052
- } catch {
1084
+ const remoteSuccess = await execWithSpinner(
1085
+ `git push origin --delete "${tagToDelete}"`,
1086
+ pushSpinner,
1087
+ `\u8FDC\u7A0B tag \u5DF2\u5220\u9664: ${tagToDelete}`
1088
+ );
1089
+ if (!remoteSuccess) {
1053
1090
  pushSpinner.warn(
1054
1091
  `\u8FDC\u7A0B\u5220\u9664\u5931\u8D25\uFF0C\u53EF\u7A0D\u540E\u624B\u52A8\u6267\u884C: git push origin --delete ${tagToDelete}`
1055
1092
  );
@@ -1096,25 +1133,32 @@ async function updateTag() {
1096
1133
  }
1097
1134
  divider();
1098
1135
  const spinner = ora2(`\u6B63\u5728\u91CD\u547D\u540D tag: ${oldTag} \u2192 ${newTag}`).start();
1099
- try {
1100
- const commit2 = execOutput(`git rev-list -n 1 "${oldTag}"`).trim();
1101
- const message = execOutput(
1102
- `git tag -l --format='%(contents)' "${oldTag}"`
1103
- ).trim();
1104
- if (message) {
1105
- execSync3(`git tag -a "${newTag}" "${commit2}" -m "${message}"`, {
1106
- stdio: "pipe"
1107
- });
1108
- } else {
1109
- execSync3(`git tag "${newTag}" "${commit2}"`, { stdio: "pipe" });
1110
- }
1111
- execSync3(`git tag -d "${oldTag}"`, { stdio: "pipe" });
1112
- spinner.succeed(`Tag \u5DF2\u91CD\u547D\u540D: ${oldTag} \u2192 ${newTag}`);
1113
- } catch (error) {
1136
+ const commit2 = execOutput(`git rev-list -n 1 "${oldTag}"`).trim();
1137
+ const message = execOutput(
1138
+ `git tag -l --format='%(contents)' "${oldTag}"`
1139
+ ).trim();
1140
+ let createSuccess;
1141
+ if (message) {
1142
+ createSuccess = await execWithSpinner(
1143
+ `git tag -a "${newTag}" "${commit2}" -m "${message}"`,
1144
+ spinner
1145
+ );
1146
+ } else {
1147
+ createSuccess = await execWithSpinner(
1148
+ `git tag "${newTag}" "${commit2}"`,
1149
+ spinner
1150
+ );
1151
+ }
1152
+ if (!createSuccess) {
1114
1153
  spinner.fail("tag \u91CD\u547D\u540D\u5931\u8D25");
1115
- console.log(colors.red(String(error)));
1116
1154
  return;
1117
1155
  }
1156
+ const deleteSuccess = await execAsync(`git tag -d "${oldTag}"`, spinner);
1157
+ if (!deleteSuccess) {
1158
+ spinner.fail("\u5220\u9664\u65E7 tag \u5931\u8D25");
1159
+ return;
1160
+ }
1161
+ spinner.succeed(`Tag \u5DF2\u91CD\u547D\u540D: ${oldTag} \u2192 ${newTag}`);
1118
1162
  const pushRemote = await select2({
1119
1163
  message: "\u662F\u5426\u540C\u6B65\u5230\u8FDC\u7A0B?",
1120
1164
  choices: [
@@ -1125,17 +1169,29 @@ async function updateTag() {
1125
1169
  });
1126
1170
  if (pushRemote) {
1127
1171
  const pushSpinner = ora2("\u6B63\u5728\u540C\u6B65\u5230\u8FDC\u7A0B...").start();
1128
- try {
1129
- execSync3(`git push origin "${newTag}"`, { stdio: "pipe" });
1130
- execSync3(`git push origin --delete "${oldTag}"`, { stdio: "pipe" });
1131
- pushSpinner.succeed(`\u8FDC\u7A0B tag \u5DF2\u540C\u6B65: ${oldTag} \u2192 ${newTag}`);
1132
- } catch {
1172
+ const pushNewSuccess = await execAsync(
1173
+ `git push origin "${newTag}"`,
1174
+ pushSpinner
1175
+ );
1176
+ if (!pushNewSuccess) {
1133
1177
  pushSpinner.warn(
1134
1178
  `\u8FDC\u7A0B\u540C\u6B65\u5931\u8D25\uFF0C\u53EF\u7A0D\u540E\u624B\u52A8\u6267\u884C:
1135
1179
  git push origin ${newTag}
1136
1180
  git push origin --delete ${oldTag}`
1137
1181
  );
1182
+ return;
1138
1183
  }
1184
+ const deleteOldSuccess = await execAsync(
1185
+ `git push origin --delete "${oldTag}"`,
1186
+ pushSpinner
1187
+ );
1188
+ if (!deleteOldSuccess) {
1189
+ pushSpinner.warn(
1190
+ `\u8FDC\u7A0B\u65E7 tag \u5220\u9664\u5931\u8D25\uFF0C\u53EF\u7A0D\u540E\u624B\u52A8\u6267\u884C: git push origin --delete ${oldTag}`
1191
+ );
1192
+ return;
1193
+ }
1194
+ pushSpinner.succeed(`\u8FDC\u7A0B tag \u5DF2\u540C\u6B65: ${oldTag} \u2192 ${newTag}`);
1139
1195
  }
1140
1196
  }
1141
1197
  async function cleanInvalidTags() {
@@ -1185,10 +1241,10 @@ async function cleanInvalidTags() {
1185
1241
  let localSuccess = 0;
1186
1242
  let localFailed = 0;
1187
1243
  for (const tag of invalidTags) {
1188
- try {
1189
- execSync3(`git tag -d "${tag}"`, { stdio: "pipe" });
1244
+ const success = await execAsync(`git tag -d "${tag}"`, localSpinner);
1245
+ if (success) {
1190
1246
  localSuccess++;
1191
- } catch {
1247
+ } else {
1192
1248
  localFailed++;
1193
1249
  }
1194
1250
  }
@@ -1212,10 +1268,13 @@ async function cleanInvalidTags() {
1212
1268
  let remoteSuccess = 0;
1213
1269
  let remoteFailed = 0;
1214
1270
  for (const tag of invalidTags) {
1215
- try {
1216
- execSync3(`git push origin --delete "${tag}"`, { stdio: "pipe" });
1271
+ const success = await execAsync(
1272
+ `git push origin --delete "${tag}"`,
1273
+ remoteSpinner
1274
+ );
1275
+ if (success) {
1217
1276
  remoteSuccess++;
1218
- } catch {
1277
+ } else {
1219
1278
  remoteFailed++;
1220
1279
  }
1221
1280
  }
@@ -1675,7 +1734,7 @@ async function init() {
1675
1734
 
1676
1735
  // src/commands/stash.ts
1677
1736
  init_utils();
1678
- import { execSync as execSync4, spawn } from "child_process";
1737
+ import { spawn as spawn2 } from "child_process";
1679
1738
  import { select as select5, input as input4 } from "@inquirer/prompts";
1680
1739
  import ora3 from "ora";
1681
1740
  import boxen from "boxen";
@@ -1779,10 +1838,10 @@ async function showStashActions(entry) {
1779
1838
  });
1780
1839
  switch (action) {
1781
1840
  case "apply":
1782
- applyStash(entry.index, false);
1841
+ await applyStash(entry.index, false);
1783
1842
  break;
1784
1843
  case "pop":
1785
- applyStash(entry.index, true);
1844
+ await applyStash(entry.index, true);
1786
1845
  break;
1787
1846
  case "branch":
1788
1847
  await createBranchFromStash(entry.index);
@@ -1822,25 +1881,29 @@ async function createStash() {
1822
1881
  theme
1823
1882
  });
1824
1883
  const spinner = ora3("\u521B\u5EFA stash...").start();
1825
- try {
1826
- let cmd = "git stash push";
1827
- if (includeUntracked) cmd += " -u";
1828
- if (message) cmd += ` -m "${message.replace(/"/g, '\\"')}"`;
1829
- execSync4(cmd, { stdio: "pipe" });
1830
- spinner.succeed("Stash \u521B\u5EFA\u6210\u529F");
1884
+ let cmd = "git stash push";
1885
+ if (includeUntracked) cmd += " -u";
1886
+ if (message) cmd += ` -m "${message.replace(/"/g, '\\"')}"`;
1887
+ const success = await execWithSpinner(
1888
+ cmd,
1889
+ spinner,
1890
+ "Stash \u521B\u5EFA\u6210\u529F",
1891
+ "Stash \u521B\u5EFA\u5931\u8D25"
1892
+ );
1893
+ if (success) {
1831
1894
  await stash();
1832
- } catch {
1833
- spinner.fail("Stash \u521B\u5EFA\u5931\u8D25");
1834
1895
  }
1835
1896
  }
1836
- function applyStash(index, pop) {
1897
+ async function applyStash(index, pop) {
1837
1898
  const action = pop ? "pop" : "apply";
1838
1899
  const spinner = ora3(`${pop ? "\u5F39\u51FA" : "\u5E94\u7528"} stash...`).start();
1839
- try {
1840
- execSync4(`git stash ${action} stash@{${index}}`, { stdio: "pipe" });
1841
- spinner.succeed(`Stash ${pop ? "\u5DF2\u5F39\u51FA" : "\u5DF2\u5E94\u7528"}`);
1842
- } catch {
1843
- spinner.fail("\u64CD\u4F5C\u5931\u8D25\uFF0C\u53EF\u80FD\u5B58\u5728\u51B2\u7A81");
1900
+ const success = await execWithSpinner(
1901
+ `git stash ${action} stash@{${index}}`,
1902
+ spinner,
1903
+ `Stash ${pop ? "\u5DF2\u5F39\u51FA" : "\u5DF2\u5E94\u7528"}`,
1904
+ "\u64CD\u4F5C\u5931\u8D25\uFF0C\u53EF\u80FD\u5B58\u5728\u51B2\u7A81"
1905
+ );
1906
+ if (!success) {
1844
1907
  const status = execOutput("git status --porcelain");
1845
1908
  if (status.includes("UU") || status.includes("AA")) {
1846
1909
  console.log(colors.yellow("\n\u5B58\u5728\u51B2\u7A81\uFF0C\u8BF7\u624B\u52A8\u89E3\u51B3\u540E\u63D0\u4EA4"));
@@ -1938,7 +2001,7 @@ function startPager(content) {
1938
2001
  return new Promise((resolve) => {
1939
2002
  const pager = process.env.PAGER || "less";
1940
2003
  try {
1941
- const pagerProcess = spawn(pager, ["-R", "-S", "-F", "-X", "-i"], {
2004
+ const pagerProcess = spawn2(pager, ["-R", "-S", "-F", "-X", "-i"], {
1942
2005
  stdio: ["pipe", "inherit", "inherit"],
1943
2006
  env: { ...process.env, LESS: "-R -S -F -X -i" }
1944
2007
  });
@@ -1979,14 +2042,12 @@ async function createBranchFromStash(index) {
1979
2042
  const branchName = await getBranchName(type);
1980
2043
  if (!branchName) return;
1981
2044
  const spinner = ora3(`\u521B\u5EFA\u5206\u652F ${branchName}...`).start();
1982
- try {
1983
- execSync4(`git stash branch "${branchName}" stash@{${index}}`, {
1984
- stdio: "pipe"
1985
- });
1986
- spinner.succeed(`\u5206\u652F\u5DF2\u521B\u5EFA: ${branchName} (stash \u5DF2\u81EA\u52A8\u5F39\u51FA)`);
1987
- } catch {
1988
- spinner.fail("\u521B\u5EFA\u5206\u652F\u5931\u8D25");
1989
- }
2045
+ await execWithSpinner(
2046
+ `git stash branch "${branchName}" stash@{${index}}`,
2047
+ spinner,
2048
+ `\u5206\u652F\u5DF2\u521B\u5EFA: ${branchName} (stash \u5DF2\u81EA\u52A8\u5F39\u51FA)`,
2049
+ "\u521B\u5EFA\u5206\u652F\u5931\u8D25"
2050
+ );
1990
2051
  }
1991
2052
  async function dropStash(index) {
1992
2053
  const confirmed = await select5({
@@ -2002,17 +2063,17 @@ async function dropStash(index) {
2002
2063
  return;
2003
2064
  }
2004
2065
  const spinner = ora3("\u5220\u9664 stash...").start();
2005
- try {
2006
- execSync4(`git stash drop stash@{${index}}`, { stdio: "pipe" });
2007
- spinner.succeed("Stash \u5DF2\u5220\u9664");
2008
- } catch {
2009
- spinner.fail("\u5220\u9664\u5931\u8D25");
2010
- }
2066
+ await execWithSpinner(
2067
+ `git stash drop stash@{${index}}`,
2068
+ spinner,
2069
+ "Stash \u5DF2\u5220\u9664",
2070
+ "\u5220\u9664\u5931\u8D25"
2071
+ );
2011
2072
  }
2012
2073
 
2013
2074
  // src/commands/commit.ts
2014
2075
  init_utils();
2015
- import { execSync as execSync5 } from "child_process";
2076
+ import { execSync as execSync2 } from "child_process";
2016
2077
  import { writeFileSync as writeFileSync3, unlinkSync } from "fs";
2017
2078
  import { tmpdir } from "os";
2018
2079
  import { join as join3 } from "path";
@@ -2430,7 +2491,7 @@ async function commit() {
2430
2491
  const config2 = getConfig();
2431
2492
  const autoStage = config2.autoStage ?? true;
2432
2493
  if (autoStage) {
2433
- execSync5("git add -A", { stdio: "pipe" });
2494
+ execSync2("git add -A", { stdio: "pipe" });
2434
2495
  }
2435
2496
  let { staged, unstaged } = parseGitStatus();
2436
2497
  if (staged.length === 0 && unstaged.length > 0 && !autoStage) {
@@ -2455,7 +2516,7 @@ async function commit() {
2455
2516
  return;
2456
2517
  }
2457
2518
  for (const file of filesToStage) {
2458
- execSync5(`git add "${file}"`, { stdio: "pipe" });
2519
+ execSync2(`git add "${file}"`, { stdio: "pipe" });
2459
2520
  }
2460
2521
  console.log(colors.green(`\u2714 \u5DF2\u6682\u5B58 ${filesToStage.length} \u4E2A\u6587\u4EF6`));
2461
2522
  divider();
@@ -2547,7 +2608,7 @@ async function commit() {
2547
2608
  const spinner = ora4("\u6B63\u5728\u63D0\u4EA4...").start();
2548
2609
  try {
2549
2610
  if (autoStage) {
2550
- execSync5("git add -A", { stdio: "pipe" });
2611
+ execSync2("git add -A", { stdio: "pipe" });
2551
2612
  }
2552
2613
  const finalStatus = parseGitStatus();
2553
2614
  if (finalStatus.staged.length === 0) {
@@ -2563,7 +2624,7 @@ async function commit() {
2563
2624
  const tmpFile = join3(tmpdir(), `.gw-commit-msg-${Date.now()}`);
2564
2625
  try {
2565
2626
  writeFileSync3(tmpFile, message, "utf-8");
2566
- execSync5(`git commit -F "${tmpFile}"`, {
2627
+ execSync2(`git commit -F "${tmpFile}"`, {
2567
2628
  stdio: ["pipe", "pipe", "pipe"]
2568
2629
  });
2569
2630
  } finally {
@@ -2674,7 +2735,7 @@ init_update_notifier();
2674
2735
 
2675
2736
  // src/commands/update.ts
2676
2737
  init_utils();
2677
- import { execSync as execSync7 } from "child_process";
2738
+ import { execSync as execSync4, spawn as spawn3 } from "child_process";
2678
2739
  import ora6 from "ora";
2679
2740
  import boxen3 from "boxen";
2680
2741
  import semver2 from "semver";
@@ -2693,7 +2754,7 @@ function clearUpdateCache2() {
2693
2754
  }
2694
2755
  async function getLatestVersion2(packageName) {
2695
2756
  try {
2696
- const result = execSync7(`npm view ${packageName} version`, {
2757
+ const result = execSync4(`npm view ${packageName} version`, {
2697
2758
  encoding: "utf-8",
2698
2759
  timeout: 3e3,
2699
2760
  stdio: ["pipe", "pipe", "ignore"]
@@ -2705,7 +2766,7 @@ async function getLatestVersion2(packageName) {
2705
2766
  }
2706
2767
  function isUsingVolta2() {
2707
2768
  try {
2708
- const whichGw = execSync7("which gw", { encoding: "utf-8" }).trim();
2769
+ const whichGw = execSync4("which gw", { encoding: "utf-8" }).trim();
2709
2770
  return whichGw.includes(".volta");
2710
2771
  } catch {
2711
2772
  return false;
@@ -2765,44 +2826,73 @@ async function update(currentVersion) {
2765
2826
  }
2766
2827
  )
2767
2828
  );
2768
- const updateSpinner = ora6("\u6B63\u5728\u66F4\u65B0...").start();
2829
+ console.log("");
2830
+ console.log(colors.cyan("\u{1F4E6} \u5F00\u59CB\u5B89\u88C5\u65B0\u7248\u672C..."));
2831
+ console.log("");
2769
2832
  const updateCommand = usingVolta ? `volta install ${packageName}@latest` : `npm install -g ${packageName}@latest`;
2770
- execSync7(updateCommand, {
2771
- encoding: "utf-8",
2772
- stdio: ["pipe", "pipe", "pipe"]
2833
+ const [command, ...args] = updateCommand.split(" ");
2834
+ const updateProcess = spawn3(command, args, {
2835
+ stdio: "inherit"
2836
+ // 继承父进程的 stdio,显示实时输出
2837
+ });
2838
+ updateProcess.on("close", (code) => {
2839
+ console.log("");
2840
+ if (code === 0) {
2841
+ console.log(colors.green("\u2714 \u66F4\u65B0\u6210\u529F\uFF01"));
2842
+ clearUpdateCache2();
2843
+ console.log("");
2844
+ console.log(
2845
+ boxen3(
2846
+ [
2847
+ colors.green(colors.bold("\u2728 \u66F4\u65B0\u5B8C\u6210\uFF01")),
2848
+ "",
2849
+ `\u65B0\u7248\u672C: ${colors.green(colors.bold(latestVersion))}`,
2850
+ "",
2851
+ colors.dim("\u8BF7\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4\u9A8C\u8BC1:"),
2852
+ colors.cyan(" hash -r && gw --version"),
2853
+ "",
2854
+ colors.dim("\u6216\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF")
2855
+ ].join("\n"),
2856
+ {
2857
+ padding: { top: 1, bottom: 1, left: 2, right: 2 },
2858
+ margin: { top: 0, bottom: 1, left: 2, right: 2 },
2859
+ borderStyle: "round",
2860
+ borderColor: "green",
2861
+ align: "left",
2862
+ width: 40
2863
+ }
2864
+ )
2865
+ );
2866
+ process.exit(0);
2867
+ } else {
2868
+ console.log(colors.red("\u2716 \u66F4\u65B0\u5931\u8D25"));
2869
+ console.log("");
2870
+ console.log(colors.dim(" \u4F60\u53EF\u4EE5\u624B\u52A8\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u66F4\u65B0:"));
2871
+ console.log(colors.cyan(` ${updateCommand}`));
2872
+ console.log("");
2873
+ process.exit(1);
2874
+ }
2875
+ });
2876
+ updateProcess.on("error", (error) => {
2877
+ console.log("");
2878
+ console.log(colors.red("\u2716 \u66F4\u65B0\u5931\u8D25"));
2879
+ console.log("");
2880
+ console.log(colors.dim(" \u4F60\u53EF\u4EE5\u624B\u52A8\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u66F4\u65B0:"));
2881
+ console.log(colors.cyan(` ${updateCommand}`));
2882
+ console.log("");
2883
+ console.log(colors.dim(` \u9519\u8BEF\u4FE1\u606F: ${error.message}`));
2884
+ console.log("");
2885
+ process.exit(1);
2773
2886
  });
2774
- updateSpinner.succeed(colors.green("\u66F4\u65B0\u6210\u529F\uFF01"));
2775
- clearUpdateCache2();
2776
- console.log("");
2777
- console.log(
2778
- boxen3(
2779
- [
2780
- colors.green(colors.bold("\u2728 \u66F4\u65B0\u5B8C\u6210\uFF01")),
2781
- "",
2782
- `\u65B0\u7248\u672C: ${colors.green(colors.bold(latestVersion))}`,
2783
- "",
2784
- colors.dim("\u8BF7\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4\u9A8C\u8BC1:"),
2785
- colors.cyan(" hash -r && gw --version"),
2786
- "",
2787
- colors.dim("\u6216\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF")
2788
- ].join("\n"),
2789
- {
2790
- padding: { top: 1, bottom: 1, left: 2, right: 2 },
2791
- margin: { top: 0, bottom: 1, left: 2, right: 2 },
2792
- borderStyle: "round",
2793
- borderColor: "green",
2794
- align: "left",
2795
- width: 40
2796
- }
2797
- )
2798
- );
2799
2887
  process.exit(0);
2800
2888
  } catch (error) {
2801
- spinner.fail(colors.red("\u66F4\u65B0\u5931\u8D25"));
2889
+ spinner.fail(colors.red("\u83B7\u53D6\u7248\u672C\u4FE1\u606F\u5931\u8D25"));
2802
2890
  console.log("");
2803
- console.log(colors.dim(" \u4F60\u53EF\u4EE5\u624B\u52A8\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u66F4\u65B0:"));
2804
- const updateCommand = usingVolta ? `volta install ${packageName}@latest` : `npm install -g ${packageName}@latest`;
2805
- console.log(colors.cyan(` ${updateCommand}`));
2891
+ console.log(colors.dim(" \u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u540E\u91CD\u8BD5"));
2892
+ console.log("");
2893
+ if (error instanceof Error) {
2894
+ console.log(colors.dim(` \u9519\u8BEF\u4FE1\u606F: ${error.message}`));
2895
+ }
2806
2896
  console.log("");
2807
2897
  process.exit(1);
2808
2898
  }
@@ -2810,9 +2900,9 @@ async function update(currentVersion) {
2810
2900
 
2811
2901
  // src/commands/log.ts
2812
2902
  init_utils();
2813
- import { execSync as execSync8 } from "child_process";
2903
+ import { execSync as execSync5 } from "child_process";
2814
2904
  import boxen4 from "boxen";
2815
- import { spawn as spawn2 } from "child_process";
2905
+ import { spawn as spawn4 } from "child_process";
2816
2906
  function parseGitLog(output) {
2817
2907
  const commits = [];
2818
2908
  const lines = output.trim().split("\n");
@@ -3030,7 +3120,7 @@ function formatTimelineStyle(commits) {
3030
3120
  function startInteractivePager(content) {
3031
3121
  const pager = process.env.PAGER || "less";
3032
3122
  try {
3033
- const pagerProcess = spawn2(pager, ["-R", "-S", "-F", "-X", "-i"], {
3123
+ const pagerProcess = spawn4(pager, ["-R", "-S", "-F", "-X", "-i"], {
3034
3124
  stdio: ["pipe", "inherit", "inherit"],
3035
3125
  env: { ...process.env, LESS: "-R -S -F -X -i" }
3036
3126
  });
@@ -3060,7 +3150,7 @@ function executeTimelineLog(options) {
3060
3150
  if (options.until) cmd += ` --until="${options.until}"`;
3061
3151
  if (options.grep) cmd += ` --grep="${options.grep}"`;
3062
3152
  if (options.all) cmd += ` --all`;
3063
- const output = execSync8(cmd, {
3153
+ const output = execSync5(cmd, {
3064
3154
  encoding: "utf8",
3065
3155
  stdio: "pipe",
3066
3156
  maxBuffer: 1024 * 1024 * 10
@@ -3120,7 +3210,7 @@ async function log(options = {}) {
3120
3210
 
3121
3211
  // src/commands/amend-date.ts
3122
3212
  init_utils();
3123
- import { execSync as execSync9 } from "child_process";
3213
+ import { execSync as execSync6 } from "child_process";
3124
3214
  import { select as select8, input as input6, confirm } from "@inquirer/prompts";
3125
3215
  function formatGitDate(date) {
3126
3216
  const year = date.getFullYear();
@@ -3243,7 +3333,7 @@ async function amendDate(commitHash) {
3243
3333
  }
3244
3334
  try {
3245
3335
  if (isLatestCommit) {
3246
- execSync9(
3336
+ execSync6(
3247
3337
  `GIT_AUTHOR_DATE="${formattedDate}" GIT_COMMITTER_DATE="${formattedDate}" git commit --amend --no-edit --reset-author`,
3248
3338
  { stdio: "pipe", shell: "/bin/bash" }
3249
3339
  );
@@ -3254,7 +3344,7 @@ async function amendDate(commitHash) {
3254
3344
  console.log(colors.cyan("\u6B63\u5728\u6267\u884C rebase..."));
3255
3345
  const parentHash = execOutput(`git rev-parse ${selectedCommit.hash}^`);
3256
3346
  const filterCmd = `git filter-branch -f --env-filter 'if [ "$GIT_COMMIT" = "${selectedCommit.hash}" ]; then export GIT_AUTHOR_DATE="${formattedDate}"; export GIT_COMMITTER_DATE="${formattedDate}"; fi' ${parentHash}..HEAD`;
3257
- execSync9(filterCmd, { stdio: "pipe" });
3347
+ execSync6(filterCmd, { stdio: "pipe" });
3258
3348
  console.log(colors.green("\u2714 \u4FEE\u6539\u6210\u529F"));
3259
3349
  console.log("");
3260
3350
  console.log(colors.yellow("\u26A0\uFE0F \u6CE8\u610F: commit hash \u5DF2\u6539\u53D8"));
@@ -3275,7 +3365,7 @@ async function amendDate(commitHash) {
3275
3365
 
3276
3366
  // src/commands/amend.ts
3277
3367
  init_utils();
3278
- import { execSync as execSync10 } from "child_process";
3368
+ import { execSync as execSync7 } from "child_process";
3279
3369
  import { select as select9, input as input7, confirm as confirm2 } from "@inquirer/prompts";
3280
3370
  function getRecentCommits2(limit = 20) {
3281
3371
  const output = execOutput(`git log -${limit} --pretty=format:"%H|%s|%ai"`);
@@ -3370,7 +3460,7 @@ async function amend(commitHash) {
3370
3460
  }
3371
3461
  try {
3372
3462
  if (isLatestCommit) {
3373
- execSync10(`git commit --amend -m "${newMessage.replace(/"/g, '\\"')}"`, {
3463
+ execSync7(`git commit --amend -m "${newMessage.replace(/"/g, '\\"')}"`, {
3374
3464
  stdio: "pipe"
3375
3465
  });
3376
3466
  console.log("");
@@ -3385,7 +3475,7 @@ if [ "$1" = "${selectedCommit.hash}" ]; then
3385
3475
  fi
3386
3476
  `;
3387
3477
  const filterCmd = `git filter-branch -f --msg-filter 'if [ "$GIT_COMMIT" = "${selectedCommit.hash}" ]; then echo "${newMessage.replace(/"/g, '\\"')}"; else cat; fi' ${parentHash}..HEAD`;
3388
- execSync10(filterCmd, { stdio: "pipe" });
3478
+ execSync7(filterCmd, { stdio: "pipe" });
3389
3479
  console.log(colors.green("\u2714 \u4FEE\u6539\u6210\u529F"));
3390
3480
  console.log("");
3391
3481
  console.log(colors.yellow("\u26A0\uFE0F \u6CE8\u610F: commit hash \u5DF2\u6539\u53D8"));
@@ -3429,7 +3519,7 @@ process.on("SIGTERM", () => {
3429
3519
  console.log("");
3430
3520
  process.exit(0);
3431
3521
  });
3432
- var version = true ? "0.4.3" : "0.0.0-dev";
3522
+ var version = true ? "0.4.4" : "0.0.0-dev";
3433
3523
  async function mainMenu() {
3434
3524
  console.log(
3435
3525
  colors.green(`