@zjex/git-workflow 0.4.2 → 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/CHANGELOG.md +26 -0
- package/README.md +1 -1
- package/dist/index.js +580 -178
- package/docs/.vitepress/config.ts +2 -0
- package/docs/commands/amend-date.md +425 -0
- package/docs/commands/amend.md +380 -0
- package/docs/commands/index.md +14 -10
- package/package.json +1 -1
- package/src/commands/amend-date.ts +228 -0
- package/src/commands/amend.ts +189 -0
- package/src/commands/branch.ts +47 -38
- package/src/commands/stash.ts +40 -33
- package/src/commands/tag.ts +113 -73
- package/src/commands/update.ts +77 -44
- package/src/index.ts +39 -4
- package/src/utils.ts +59 -1
- package/tests/amend-date.test.ts +364 -0
- package/tests/amend.test.ts +441 -0
- package/tests/stash.test.ts +70 -75
- package/tests/update.test.ts +125 -112
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
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
278
|
+
execSync3(updateCommand, {
|
|
248
279
|
encoding: "utf-8",
|
|
249
280
|
stdio: ["pipe", "pipe", "pipe"]
|
|
250
281
|
});
|
|
@@ -322,12 +353,11 @@ var init_update_notifier = __esm({
|
|
|
322
353
|
// src/index.ts
|
|
323
354
|
init_utils();
|
|
324
355
|
import { cac } from "cac";
|
|
325
|
-
import { select as
|
|
356
|
+
import { select as select10 } from "@inquirer/prompts";
|
|
326
357
|
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
|
-
|
|
515
|
-
|
|
516
|
-
pushSpinner
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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
|
}
|
|
@@ -573,7 +606,7 @@ async function deleteBranch(branchArg) {
|
|
|
573
606
|
}
|
|
574
607
|
if (branch.startsWith("__remote__")) {
|
|
575
608
|
const remoteBranch = branch.replace("__remote__", "");
|
|
576
|
-
const
|
|
609
|
+
const confirm3 = await select({
|
|
577
610
|
message: `\u786E\u8BA4\u5220\u9664\u8FDC\u7A0B\u5206\u652F origin/${remoteBranch}?`,
|
|
578
611
|
choices: [
|
|
579
612
|
{ name: "\u662F", value: true },
|
|
@@ -581,19 +614,17 @@ async function deleteBranch(branchArg) {
|
|
|
581
614
|
],
|
|
582
615
|
theme
|
|
583
616
|
});
|
|
584
|
-
if (!
|
|
617
|
+
if (!confirm3) {
|
|
585
618
|
console.log(colors.yellow("\u5DF2\u53D6\u6D88"));
|
|
586
619
|
return;
|
|
587
620
|
}
|
|
588
621
|
const spinner = ora(`\u6B63\u5728\u5220\u9664\u8FDC\u7A0B\u5206\u652F: origin/${remoteBranch}`).start();
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
|
|
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
|
-
|
|
622
|
-
|
|
623
|
-
spinner
|
|
624
|
-
|
|
625
|
-
|
|
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
|
-
|
|
647
|
-
|
|
648
|
-
localSpinner
|
|
649
|
-
|
|
650
|
-
|
|
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
|
-
|
|
656
|
-
|
|
657
|
-
remoteSpinner
|
|
658
|
-
|
|
659
|
-
|
|
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
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
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
|
-
|
|
989
|
-
|
|
990
|
-
pushSpinner
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
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() {
|
|
@@ -1015,7 +1048,7 @@ async function deleteTag() {
|
|
|
1015
1048
|
console.log(colors.yellow("\u5DF2\u53D6\u6D88"));
|
|
1016
1049
|
return;
|
|
1017
1050
|
}
|
|
1018
|
-
const
|
|
1051
|
+
const confirm3 = await select2({
|
|
1019
1052
|
message: `\u786E\u8BA4\u5220\u9664 tag: ${colors.red(tagToDelete)}?`,
|
|
1020
1053
|
choices: [
|
|
1021
1054
|
{ name: "\u662F", value: true },
|
|
@@ -1023,17 +1056,19 @@ async function deleteTag() {
|
|
|
1023
1056
|
],
|
|
1024
1057
|
theme
|
|
1025
1058
|
});
|
|
1026
|
-
if (!
|
|
1059
|
+
if (!confirm3) {
|
|
1027
1060
|
console.log(colors.yellow("\u5DF2\u53D6\u6D88"));
|
|
1028
1061
|
return;
|
|
1029
1062
|
}
|
|
1030
1063
|
divider();
|
|
1031
1064
|
const spinner = ora2(`\u6B63\u5728\u5220\u9664\u672C\u5730 tag: ${tagToDelete}`).start();
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
spinner
|
|
1035
|
-
|
|
1036
|
-
|
|
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
|
-
|
|
1050
|
-
|
|
1051
|
-
pushSpinner
|
|
1052
|
-
|
|
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
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
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
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
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;
|
|
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;
|
|
1138
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
|
-
|
|
1189
|
-
|
|
1244
|
+
const success = await execAsync(`git tag -d "${tag}"`, localSpinner);
|
|
1245
|
+
if (success) {
|
|
1190
1246
|
localSuccess++;
|
|
1191
|
-
}
|
|
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
|
-
|
|
1216
|
-
|
|
1271
|
+
const success = await execAsync(
|
|
1272
|
+
`git push origin --delete "${tag}"`,
|
|
1273
|
+
remoteSpinner
|
|
1274
|
+
);
|
|
1275
|
+
if (success) {
|
|
1217
1276
|
remoteSuccess++;
|
|
1218
|
-
}
|
|
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 {
|
|
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
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
spinner
|
|
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
|
-
|
|
1840
|
-
|
|
1841
|
-
spinner
|
|
1842
|
-
|
|
1843
|
-
|
|
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 =
|
|
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
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
})
|
|
1986
|
-
|
|
1987
|
-
|
|
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
|
-
|
|
2006
|
-
|
|
2007
|
-
spinner
|
|
2008
|
-
|
|
2009
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
2771
|
-
|
|
2772
|
-
stdio:
|
|
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("\
|
|
2889
|
+
spinner.fail(colors.red("\u83B7\u53D6\u7248\u672C\u4FE1\u606F\u5931\u8D25"));
|
|
2802
2890
|
console.log("");
|
|
2803
|
-
console.log(colors.dim(" \
|
|
2804
|
-
|
|
2805
|
-
|
|
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
|
|
2903
|
+
import { execSync as execSync5 } from "child_process";
|
|
2814
2904
|
import boxen4 from "boxen";
|
|
2815
|
-
import { spawn as
|
|
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 =
|
|
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 =
|
|
3153
|
+
const output = execSync5(cmd, {
|
|
3064
3154
|
encoding: "utf8",
|
|
3065
3155
|
stdio: "pipe",
|
|
3066
3156
|
maxBuffer: 1024 * 1024 * 10
|
|
@@ -3118,6 +3208,292 @@ async function log(options = {}) {
|
|
|
3118
3208
|
executeTimelineLog(options);
|
|
3119
3209
|
}
|
|
3120
3210
|
|
|
3211
|
+
// src/commands/amend-date.ts
|
|
3212
|
+
init_utils();
|
|
3213
|
+
import { execSync as execSync6 } from "child_process";
|
|
3214
|
+
import { select as select8, input as input6, confirm } from "@inquirer/prompts";
|
|
3215
|
+
function formatGitDate(date) {
|
|
3216
|
+
const year = date.getFullYear();
|
|
3217
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
3218
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
3219
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
3220
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
3221
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
3222
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
3223
|
+
}
|
|
3224
|
+
function parseDate(input8) {
|
|
3225
|
+
const trimmed = input8.trim();
|
|
3226
|
+
const dateMatch = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
3227
|
+
if (dateMatch) {
|
|
3228
|
+
const [, year, month, day] = dateMatch;
|
|
3229
|
+
return new Date(
|
|
3230
|
+
parseInt(year),
|
|
3231
|
+
parseInt(month) - 1,
|
|
3232
|
+
parseInt(day),
|
|
3233
|
+
0,
|
|
3234
|
+
0,
|
|
3235
|
+
0
|
|
3236
|
+
);
|
|
3237
|
+
}
|
|
3238
|
+
return null;
|
|
3239
|
+
}
|
|
3240
|
+
function getRecentCommits(limit = 20) {
|
|
3241
|
+
const output = execOutput(`git log -${limit} --pretty=format:"%H|%s|%ai"`);
|
|
3242
|
+
if (!output) return [];
|
|
3243
|
+
return output.split("\n").map((line) => {
|
|
3244
|
+
const [hash, message, date] = line.split("|");
|
|
3245
|
+
return { hash, message, date };
|
|
3246
|
+
});
|
|
3247
|
+
}
|
|
3248
|
+
function getCommitByHash(hash) {
|
|
3249
|
+
try {
|
|
3250
|
+
const output = execOutput(`git log -1 ${hash} --pretty=format:"%H|%s|%ai"`);
|
|
3251
|
+
if (!output) return null;
|
|
3252
|
+
const [fullHash, message, date] = output.split("|");
|
|
3253
|
+
return { hash: fullHash, message, date };
|
|
3254
|
+
} catch {
|
|
3255
|
+
return null;
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
async function amendDate(commitHash) {
|
|
3259
|
+
console.log(colors.cyan("\u4FEE\u6539 Commit \u63D0\u4EA4\u65F6\u95F4"));
|
|
3260
|
+
divider();
|
|
3261
|
+
let selectedCommit;
|
|
3262
|
+
if (commitHash) {
|
|
3263
|
+
const commit2 = getCommitByHash(commitHash);
|
|
3264
|
+
if (!commit2) {
|
|
3265
|
+
console.log(colors.red(`\u2716 \u627E\u4E0D\u5230 commit: ${commitHash}`));
|
|
3266
|
+
return;
|
|
3267
|
+
}
|
|
3268
|
+
selectedCommit = commit2;
|
|
3269
|
+
} else {
|
|
3270
|
+
const commits = getRecentCommits(20);
|
|
3271
|
+
if (commits.length === 0) {
|
|
3272
|
+
console.log(colors.yellow("\u6CA1\u6709\u627E\u5230\u4EFB\u4F55 commit"));
|
|
3273
|
+
return;
|
|
3274
|
+
}
|
|
3275
|
+
selectedCommit = await select8({
|
|
3276
|
+
message: "\u9009\u62E9\u8981\u4FEE\u6539\u65F6\u95F4\u7684 commit:",
|
|
3277
|
+
choices: commits.map((c) => ({
|
|
3278
|
+
name: `${colors.yellow(c.hash.slice(0, 7))} ${c.message.slice(0, 60)} ${colors.dim(c.date)}`,
|
|
3279
|
+
value: c,
|
|
3280
|
+
description: c.date
|
|
3281
|
+
})),
|
|
3282
|
+
pageSize: 15,
|
|
3283
|
+
theme
|
|
3284
|
+
});
|
|
3285
|
+
}
|
|
3286
|
+
console.log("");
|
|
3287
|
+
console.log("\u5F53\u524D commit \u4FE1\u606F:");
|
|
3288
|
+
console.log(` Hash: ${colors.yellow(selectedCommit.hash.slice(0, 7))}`);
|
|
3289
|
+
console.log(` Message: ${selectedCommit.message}`);
|
|
3290
|
+
console.log(` Date: ${colors.cyan(selectedCommit.date)}`);
|
|
3291
|
+
divider();
|
|
3292
|
+
console.log(colors.dim("\u8F93\u5165\u65E5\u671F\u683C\u5F0F: YYYY-MM-DD (\u5982: 2026-01-19)"));
|
|
3293
|
+
console.log("");
|
|
3294
|
+
const dateInput = await input6({
|
|
3295
|
+
message: "\u8F93\u5165\u65B0\u7684\u65E5\u671F:",
|
|
3296
|
+
validate: (value) => {
|
|
3297
|
+
const parsed = parseDate(value);
|
|
3298
|
+
if (!parsed) {
|
|
3299
|
+
return "\u65E5\u671F\u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u8BF7\u4F7F\u7528 YYYY-MM-DD \u683C\u5F0F";
|
|
3300
|
+
}
|
|
3301
|
+
return true;
|
|
3302
|
+
},
|
|
3303
|
+
theme
|
|
3304
|
+
});
|
|
3305
|
+
const newDate = parseDate(dateInput);
|
|
3306
|
+
const formattedDate = formatGitDate(newDate);
|
|
3307
|
+
divider();
|
|
3308
|
+
console.log("\u4FEE\u6539\u9884\u89C8:");
|
|
3309
|
+
console.log(` Commit: ${colors.yellow(selectedCommit.hash.slice(0, 7))}`);
|
|
3310
|
+
console.log(` \u65E7\u65F6\u95F4: ${colors.dim(selectedCommit.date)}`);
|
|
3311
|
+
console.log(` \u65B0\u65F6\u95F4: ${colors.green(formattedDate)}`);
|
|
3312
|
+
console.log(` \u4FEE\u6539\u7C7B\u578B: Author + Committer (\u4E24\u8005\u90FD\u4FEE\u6539)`);
|
|
3313
|
+
divider();
|
|
3314
|
+
const latestHash = execOutput("git rev-parse HEAD");
|
|
3315
|
+
const isLatestCommit = selectedCommit.hash === latestHash;
|
|
3316
|
+
if (!isLatestCommit) {
|
|
3317
|
+
console.log(
|
|
3318
|
+
colors.yellow(
|
|
3319
|
+
"\u26A0\uFE0F \u8B66\u544A: \u4FEE\u6539\u975E\u6700\u65B0 commit \u9700\u8981\u4F7F\u7528 rebase\uFF0C\u53EF\u80FD\u4F1A\u6539\u53D8 commit hash"
|
|
3320
|
+
)
|
|
3321
|
+
);
|
|
3322
|
+
console.log(colors.dim(" \u8FD9\u4F1A\u5F71\u54CD\u5DF2\u63A8\u9001\u5230\u8FDC\u7A0B\u7684 commit\uFF0C\u8BF7\u8C28\u614E\u64CD\u4F5C"));
|
|
3323
|
+
console.log("");
|
|
3324
|
+
}
|
|
3325
|
+
const shouldProceed = await confirm({
|
|
3326
|
+
message: "\u786E\u8BA4\u4FEE\u6539?",
|
|
3327
|
+
default: false,
|
|
3328
|
+
theme
|
|
3329
|
+
});
|
|
3330
|
+
if (!shouldProceed) {
|
|
3331
|
+
console.log(colors.yellow("\u5DF2\u53D6\u6D88"));
|
|
3332
|
+
return;
|
|
3333
|
+
}
|
|
3334
|
+
try {
|
|
3335
|
+
if (isLatestCommit) {
|
|
3336
|
+
execSync6(
|
|
3337
|
+
`GIT_AUTHOR_DATE="${formattedDate}" GIT_COMMITTER_DATE="${formattedDate}" git commit --amend --no-edit --reset-author`,
|
|
3338
|
+
{ stdio: "pipe", shell: "/bin/bash" }
|
|
3339
|
+
);
|
|
3340
|
+
console.log("");
|
|
3341
|
+
console.log(colors.green("\u2714 \u4FEE\u6539\u6210\u529F"));
|
|
3342
|
+
} else {
|
|
3343
|
+
console.log("");
|
|
3344
|
+
console.log(colors.cyan("\u6B63\u5728\u6267\u884C rebase..."));
|
|
3345
|
+
const parentHash = execOutput(`git rev-parse ${selectedCommit.hash}^`);
|
|
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`;
|
|
3347
|
+
execSync6(filterCmd, { stdio: "pipe" });
|
|
3348
|
+
console.log(colors.green("\u2714 \u4FEE\u6539\u6210\u529F"));
|
|
3349
|
+
console.log("");
|
|
3350
|
+
console.log(colors.yellow("\u26A0\uFE0F \u6CE8\u610F: commit hash \u5DF2\u6539\u53D8"));
|
|
3351
|
+
console.log(colors.dim(" \u5982\u679C\u5DF2\u63A8\u9001\u5230\u8FDC\u7A0B\uFF0C\u9700\u8981\u4F7F\u7528 force push:"));
|
|
3352
|
+
console.log(colors.cyan(" git push --force-with-lease"));
|
|
3353
|
+
}
|
|
3354
|
+
console.log("");
|
|
3355
|
+
} catch (error) {
|
|
3356
|
+
console.log("");
|
|
3357
|
+
console.log(colors.red("\u2716 \u4FEE\u6539\u5931\u8D25"));
|
|
3358
|
+
if (error instanceof Error) {
|
|
3359
|
+
console.log(colors.dim(error.message));
|
|
3360
|
+
}
|
|
3361
|
+
console.log("");
|
|
3362
|
+
throw error;
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
|
|
3366
|
+
// src/commands/amend.ts
|
|
3367
|
+
init_utils();
|
|
3368
|
+
import { execSync as execSync7 } from "child_process";
|
|
3369
|
+
import { select as select9, input as input7, confirm as confirm2 } from "@inquirer/prompts";
|
|
3370
|
+
function getRecentCommits2(limit = 20) {
|
|
3371
|
+
const output = execOutput(`git log -${limit} --pretty=format:"%H|%s|%ai"`);
|
|
3372
|
+
if (!output) return [];
|
|
3373
|
+
return output.split("\n").map((line) => {
|
|
3374
|
+
const [hash, message, date] = line.split("|");
|
|
3375
|
+
return { hash, message, date };
|
|
3376
|
+
});
|
|
3377
|
+
}
|
|
3378
|
+
function getCommitByHash2(hash) {
|
|
3379
|
+
try {
|
|
3380
|
+
const output = execOutput(`git log -1 ${hash} --pretty=format:"%H|%s|%ai"`);
|
|
3381
|
+
if (!output) return null;
|
|
3382
|
+
const [fullHash, message, date] = output.split("|");
|
|
3383
|
+
return { hash: fullHash, message, date };
|
|
3384
|
+
} catch {
|
|
3385
|
+
return null;
|
|
3386
|
+
}
|
|
3387
|
+
}
|
|
3388
|
+
async function amend(commitHash) {
|
|
3389
|
+
console.log(colors.cyan("\u4FEE\u6539 Commit \u63D0\u4EA4\u4FE1\u606F"));
|
|
3390
|
+
divider();
|
|
3391
|
+
let selectedCommit;
|
|
3392
|
+
if (commitHash) {
|
|
3393
|
+
const commit2 = getCommitByHash2(commitHash);
|
|
3394
|
+
if (!commit2) {
|
|
3395
|
+
console.log(colors.red(`\u2716 \u627E\u4E0D\u5230 commit: ${commitHash}`));
|
|
3396
|
+
return;
|
|
3397
|
+
}
|
|
3398
|
+
selectedCommit = commit2;
|
|
3399
|
+
} else {
|
|
3400
|
+
const commits = getRecentCommits2(20);
|
|
3401
|
+
if (commits.length === 0) {
|
|
3402
|
+
console.log(colors.yellow("\u6CA1\u6709\u627E\u5230\u4EFB\u4F55 commit"));
|
|
3403
|
+
return;
|
|
3404
|
+
}
|
|
3405
|
+
selectedCommit = await select9({
|
|
3406
|
+
message: "\u9009\u62E9\u8981\u4FEE\u6539\u7684 commit:",
|
|
3407
|
+
choices: commits.map((c) => ({
|
|
3408
|
+
name: `${colors.yellow(c.hash.slice(0, 7))} ${c.message} ${colors.dim(c.date)}`,
|
|
3409
|
+
value: c,
|
|
3410
|
+
description: c.message
|
|
3411
|
+
})),
|
|
3412
|
+
pageSize: 15,
|
|
3413
|
+
theme
|
|
3414
|
+
});
|
|
3415
|
+
}
|
|
3416
|
+
console.log("");
|
|
3417
|
+
console.log("\u5F53\u524D commit \u4FE1\u606F:");
|
|
3418
|
+
console.log(` Hash: ${colors.yellow(selectedCommit.hash.slice(0, 7))}`);
|
|
3419
|
+
console.log(` Message: ${selectedCommit.message}`);
|
|
3420
|
+
console.log(` Date: ${colors.dim(selectedCommit.date)}`);
|
|
3421
|
+
divider();
|
|
3422
|
+
const newMessage = await input7({
|
|
3423
|
+
message: "\u8F93\u5165\u65B0\u7684 commit message:",
|
|
3424
|
+
default: selectedCommit.message,
|
|
3425
|
+
validate: (value) => {
|
|
3426
|
+
if (!value.trim()) {
|
|
3427
|
+
return "commit message \u4E0D\u80FD\u4E3A\u7A7A";
|
|
3428
|
+
}
|
|
3429
|
+
return true;
|
|
3430
|
+
},
|
|
3431
|
+
theme
|
|
3432
|
+
});
|
|
3433
|
+
divider();
|
|
3434
|
+
console.log("\u4FEE\u6539\u9884\u89C8:");
|
|
3435
|
+
console.log(
|
|
3436
|
+
` Commit: ${colors.yellow(selectedCommit.hash.slice(0, 7))}`
|
|
3437
|
+
);
|
|
3438
|
+
console.log(` \u65E7 Message: ${colors.dim(selectedCommit.message)}`);
|
|
3439
|
+
console.log(` \u65B0 Message: ${colors.green(newMessage)}`);
|
|
3440
|
+
divider();
|
|
3441
|
+
const latestHash = execOutput("git rev-parse HEAD");
|
|
3442
|
+
const isLatestCommit = selectedCommit.hash === latestHash;
|
|
3443
|
+
if (!isLatestCommit) {
|
|
3444
|
+
console.log(
|
|
3445
|
+
colors.yellow(
|
|
3446
|
+
"\u26A0\uFE0F \u8B66\u544A: \u4FEE\u6539\u975E\u6700\u65B0 commit \u9700\u8981\u4F7F\u7528 rebase\uFF0C\u53EF\u80FD\u4F1A\u6539\u53D8 commit hash"
|
|
3447
|
+
)
|
|
3448
|
+
);
|
|
3449
|
+
console.log(colors.dim(" \u8FD9\u4F1A\u5F71\u54CD\u5DF2\u63A8\u9001\u5230\u8FDC\u7A0B\u7684 commit\uFF0C\u8BF7\u8C28\u614E\u64CD\u4F5C"));
|
|
3450
|
+
console.log("");
|
|
3451
|
+
}
|
|
3452
|
+
const shouldProceed = await confirm2({
|
|
3453
|
+
message: "\u786E\u8BA4\u4FEE\u6539?",
|
|
3454
|
+
default: false,
|
|
3455
|
+
theme
|
|
3456
|
+
});
|
|
3457
|
+
if (!shouldProceed) {
|
|
3458
|
+
console.log(colors.yellow("\u5DF2\u53D6\u6D88"));
|
|
3459
|
+
return;
|
|
3460
|
+
}
|
|
3461
|
+
try {
|
|
3462
|
+
if (isLatestCommit) {
|
|
3463
|
+
execSync7(`git commit --amend -m "${newMessage.replace(/"/g, '\\"')}"`, {
|
|
3464
|
+
stdio: "pipe"
|
|
3465
|
+
});
|
|
3466
|
+
console.log("");
|
|
3467
|
+
console.log(colors.green("\u2714 \u4FEE\u6539\u6210\u529F"));
|
|
3468
|
+
} else {
|
|
3469
|
+
console.log("");
|
|
3470
|
+
console.log(colors.cyan("\u6B63\u5728\u6267\u884C rebase..."));
|
|
3471
|
+
const parentHash = execOutput(`git rev-parse ${selectedCommit.hash}^`);
|
|
3472
|
+
const rebaseScript = `#!/bin/sh
|
|
3473
|
+
if [ "$1" = "${selectedCommit.hash}" ]; then
|
|
3474
|
+
echo "${newMessage}" > "$2"
|
|
3475
|
+
fi
|
|
3476
|
+
`;
|
|
3477
|
+
const filterCmd = `git filter-branch -f --msg-filter 'if [ "$GIT_COMMIT" = "${selectedCommit.hash}" ]; then echo "${newMessage.replace(/"/g, '\\"')}"; else cat; fi' ${parentHash}..HEAD`;
|
|
3478
|
+
execSync7(filterCmd, { stdio: "pipe" });
|
|
3479
|
+
console.log(colors.green("\u2714 \u4FEE\u6539\u6210\u529F"));
|
|
3480
|
+
console.log("");
|
|
3481
|
+
console.log(colors.yellow("\u26A0\uFE0F \u6CE8\u610F: commit hash \u5DF2\u6539\u53D8"));
|
|
3482
|
+
console.log(colors.dim(" \u5982\u679C\u5DF2\u63A8\u9001\u5230\u8FDC\u7A0B\uFF0C\u9700\u8981\u4F7F\u7528 force push:"));
|
|
3483
|
+
console.log(colors.cyan(" git push --force-with-lease"));
|
|
3484
|
+
}
|
|
3485
|
+
console.log("");
|
|
3486
|
+
} catch (error) {
|
|
3487
|
+
console.log("");
|
|
3488
|
+
console.log(colors.red("\u2716 \u4FEE\u6539\u5931\u8D25"));
|
|
3489
|
+
if (error instanceof Error) {
|
|
3490
|
+
console.log(colors.dim(error.message));
|
|
3491
|
+
}
|
|
3492
|
+
console.log("");
|
|
3493
|
+
throw error;
|
|
3494
|
+
}
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3121
3497
|
// src/index.ts
|
|
3122
3498
|
process.on("uncaughtException", (err) => {
|
|
3123
3499
|
if (err instanceof ExitPromptError) {
|
|
@@ -3143,7 +3519,7 @@ process.on("SIGTERM", () => {
|
|
|
3143
3519
|
console.log("");
|
|
3144
3520
|
process.exit(0);
|
|
3145
3521
|
});
|
|
3146
|
-
var version = true ? "0.4.
|
|
3522
|
+
var version = true ? "0.4.4" : "0.0.0-dev";
|
|
3147
3523
|
async function mainMenu() {
|
|
3148
3524
|
console.log(
|
|
3149
3525
|
colors.green(`
|
|
@@ -3157,7 +3533,7 @@ async function mainMenu() {
|
|
|
3157
3533
|
);
|
|
3158
3534
|
console.log(colors.dim(` git-workflow v${colors.yellow(version)}
|
|
3159
3535
|
`));
|
|
3160
|
-
const action = await
|
|
3536
|
+
const action = await select10({
|
|
3161
3537
|
message: "\u9009\u62E9\u64CD\u4F5C:",
|
|
3162
3538
|
choices: [
|
|
3163
3539
|
{
|
|
@@ -3201,11 +3577,19 @@ async function mainMenu() {
|
|
|
3201
3577
|
value: "stash"
|
|
3202
3578
|
},
|
|
3203
3579
|
{
|
|
3204
|
-
name: `[b] \
|
|
3580
|
+
name: `[b] \u{1F4DC} \u67E5\u770B\u65E5\u5FD7 ${colors.dim("gw log")}`,
|
|
3205
3581
|
value: "log"
|
|
3206
3582
|
},
|
|
3207
3583
|
{
|
|
3208
|
-
name: `[c] \
|
|
3584
|
+
name: `[c] \u{1F550} \u4FEE\u6539\u63D0\u4EA4\u65F6\u95F4 ${colors.dim("gw ad")}`,
|
|
3585
|
+
value: "amend-date"
|
|
3586
|
+
},
|
|
3587
|
+
{
|
|
3588
|
+
name: `[d] \u270F\uFE0F \u4FEE\u6539\u63D0\u4EA4\u4FE1\u606F ${colors.dim("gw amend")}`,
|
|
3589
|
+
value: "amend"
|
|
3590
|
+
},
|
|
3591
|
+
{
|
|
3592
|
+
name: `[e] \u2699\uFE0F \u521D\u59CB\u5316\u914D\u7F6E ${colors.dim("gw init")}`,
|
|
3209
3593
|
value: "init"
|
|
3210
3594
|
},
|
|
3211
3595
|
{ name: "[0] \u2753 \u5E2E\u52A9", value: "help" },
|
|
@@ -3258,6 +3642,14 @@ async function mainMenu() {
|
|
|
3258
3642
|
checkGitRepo();
|
|
3259
3643
|
await log();
|
|
3260
3644
|
break;
|
|
3645
|
+
case "amend-date":
|
|
3646
|
+
checkGitRepo();
|
|
3647
|
+
await amendDate();
|
|
3648
|
+
break;
|
|
3649
|
+
case "amend":
|
|
3650
|
+
checkGitRepo();
|
|
3651
|
+
await amend();
|
|
3652
|
+
break;
|
|
3261
3653
|
case "init":
|
|
3262
3654
|
await init();
|
|
3263
3655
|
break;
|
|
@@ -3341,18 +3733,28 @@ cli.command("log", "\u4EA4\u4E92\u5F0FGit\u65E5\u5FD7\u67E5\u770B (\u5206\u9875\
|
|
|
3341
3733
|
if (options.limit) logOptions.limit = parseInt(options.limit);
|
|
3342
3734
|
return log(logOptions);
|
|
3343
3735
|
});
|
|
3736
|
+
cli.command("amend:date [hash]", "\u4FEE\u6539\u6307\u5B9A commit \u7684\u63D0\u4EA4\u65F6\u95F4").alias("ad").action(async (hash) => {
|
|
3737
|
+
await checkForUpdates(version, "@zjex/git-workflow");
|
|
3738
|
+
checkGitRepo();
|
|
3739
|
+
return amendDate(hash);
|
|
3740
|
+
});
|
|
3741
|
+
cli.command("amend [hash]", "\u4FEE\u6539\u6307\u5B9A commit \u7684\u63D0\u4EA4\u4FE1\u606F").action(async (hash) => {
|
|
3742
|
+
await checkForUpdates(version, "@zjex/git-workflow");
|
|
3743
|
+
checkGitRepo();
|
|
3744
|
+
return amend(hash);
|
|
3745
|
+
});
|
|
3344
3746
|
cli.command("clean", "\u6E05\u7406\u7F13\u5B58\u548C\u4E34\u65F6\u6587\u4EF6").alias("cc").action(async () => {
|
|
3345
3747
|
const { clearUpdateCache: clearUpdateCache3 } = await Promise.resolve().then(() => (init_update_notifier(), update_notifier_exports));
|
|
3346
3748
|
const { existsSync: existsSync5, unlinkSync: unlinkSync4, readdirSync } = await import("fs");
|
|
3347
3749
|
const { homedir: homedir5, tmpdir: tmpdir2 } = await import("os");
|
|
3348
3750
|
const { join: join6 } = await import("path");
|
|
3349
|
-
const { select:
|
|
3751
|
+
const { select: select11 } = await import("@inquirer/prompts");
|
|
3350
3752
|
let cleanedCount = 0;
|
|
3351
3753
|
let deletedGlobalConfig = false;
|
|
3352
3754
|
const globalConfig = join6(homedir5(), ".gwrc.json");
|
|
3353
3755
|
const hasGlobalConfig = existsSync5(globalConfig);
|
|
3354
3756
|
if (hasGlobalConfig) {
|
|
3355
|
-
const shouldDeleteConfig = await
|
|
3757
|
+
const shouldDeleteConfig = await select11({
|
|
3356
3758
|
message: "\u68C0\u6D4B\u5230\u5168\u5C40\u914D\u7F6E\u6587\u4EF6\uFF0C\u662F\u5426\u5220\u9664\uFF1F",
|
|
3357
3759
|
choices: [
|
|
3358
3760
|
{ name: "\u5426\uFF0C\u4FDD\u7559\u914D\u7F6E\u6587\u4EF6", value: false },
|