@zjex/git-workflow 0.2.9 → 0.2.10

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/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # @zjex/git-workflow
2
2
 
3
3
  <p align="center">
4
- <a href="https://www.npmjs.com/package/@zjex/git-workflow"><img src="https://img.shields.io/npm/v/@zjex/git-workflow.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="npm version"></a>
5
- <a href="https://www.npmjs.com/package/@zjex/git-workflow"><img src="https://img.shields.io/npm/dm/@zjex/git-workflow.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="npm downloads"></a>
6
- <a href="https://www.npmjs.com/package/@zjex/git-workflow"><img src="https://img.shields.io/npm/l/@zjex/git-workflow.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="license"></a>
7
- <img src="https://img.shields.io/badge/node-%3E%3D18-28CF8D?style=flat&colorA=18181B" alt="node version">
4
+ <a href="https://www.npmjs.com/package/@zjex/git-workflow"><img src="https://img.shields.io/npm/v/@zjex/git-workflow?style=flat&colorA=18181B&colorB=F0DB4F" alt="npm version"></a>
5
+ <a href="https://www.npmjs.com/package/@zjex/git-workflow"><img src="https://img.shields.io/npm/dt/@zjex/git-workflow?style=flat&colorA=18181B&colorB=3178C6" alt="npm downloads"></a>
6
+ <a href="https://github.com/iamzjt-front-end/git-workflow"><img src="https://img.shields.io/github/stars/iamzjt-front-end/git-workflow?style=flat&colorA=18181B&colorB=F59E0B" alt="github stars"></a>
7
+ <a href="https://github.com/iamzjt-front-end/git-workflow/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@zjex/git-workflow?style=flat&colorA=18181B&colorB=10B981" alt="license"></a>
8
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D18-339933?style=flat&logo=node.js&logoColor=white&colorA=18181B" alt="node version"></a>
9
+ <a href="https://github.com/iamzjt-front-end/git-workflow/issues"><img src="https://img.shields.io/github/issues/iamzjt-front-end/git-workflow?style=flat&colorA=18181B&colorB=EC4899" alt="issues"></a>
8
10
  </p>
9
11
 
10
12
  <p align="center">
package/dist/index.js CHANGED
@@ -635,6 +635,130 @@ function doCreateTag(tagName) {
635
635
  );
636
636
  }
637
637
  }
638
+ async function deleteTag() {
639
+ const fetchSpinner = ora2("\u6B63\u5728\u83B7\u53D6 tags...").start();
640
+ exec("git fetch --tags", true);
641
+ fetchSpinner.stop();
642
+ const tags = execOutput("git tag -l --sort=-v:refname").split("\n").filter(Boolean);
643
+ if (tags.length === 0) {
644
+ console.log(colors.yellow("\u6CA1\u6709\u53EF\u5220\u9664\u7684 tag"));
645
+ return;
646
+ }
647
+ divider();
648
+ const choices = tags.map((tag) => ({ name: tag, value: tag }));
649
+ choices.push({ name: "\u53D6\u6D88", value: "__cancel__" });
650
+ const tagToDelete = await select2({
651
+ message: "\u9009\u62E9\u8981\u5220\u9664\u7684 tag:",
652
+ choices,
653
+ theme
654
+ });
655
+ if (tagToDelete === "__cancel__") {
656
+ console.log(colors.yellow("\u5DF2\u53D6\u6D88"));
657
+ return;
658
+ }
659
+ const confirm = await select2({
660
+ message: `\u786E\u8BA4\u5220\u9664 tag: ${colors.red(tagToDelete)}?`,
661
+ choices: [
662
+ { name: "\u662F", value: true },
663
+ { name: "\u5426", value: false }
664
+ ],
665
+ theme
666
+ });
667
+ if (!confirm) {
668
+ console.log(colors.yellow("\u5DF2\u53D6\u6D88"));
669
+ return;
670
+ }
671
+ divider();
672
+ const spinner = ora2(`\u6B63\u5728\u5220\u9664\u672C\u5730 tag: ${tagToDelete}`).start();
673
+ try {
674
+ execSync3(`git tag -d "${tagToDelete}"`, { stdio: "pipe" });
675
+ spinner.succeed(`\u672C\u5730 tag \u5DF2\u5220\u9664: ${tagToDelete}`);
676
+ } catch {
677
+ spinner.fail("\u672C\u5730 tag \u5220\u9664\u5931\u8D25");
678
+ return;
679
+ }
680
+ const deleteRemote = await select2({
681
+ message: "\u662F\u5426\u540C\u65F6\u5220\u9664\u8FDC\u7A0B tag?",
682
+ choices: [
683
+ { name: "\u662F", value: true },
684
+ { name: "\u5426", value: false }
685
+ ],
686
+ theme
687
+ });
688
+ if (deleteRemote) {
689
+ const pushSpinner = ora2("\u6B63\u5728\u5220\u9664\u8FDC\u7A0B tag...").start();
690
+ try {
691
+ execSync3(`git push origin --delete "${tagToDelete}"`, { stdio: "pipe" });
692
+ pushSpinner.succeed(`\u8FDC\u7A0B tag \u5DF2\u5220\u9664: ${tagToDelete}`);
693
+ } catch {
694
+ pushSpinner.warn(
695
+ `\u8FDC\u7A0B\u5220\u9664\u5931\u8D25\uFF0C\u53EF\u7A0D\u540E\u624B\u52A8\u6267\u884C: git push origin --delete ${tagToDelete}`
696
+ );
697
+ }
698
+ }
699
+ }
700
+ async function updateTag() {
701
+ const fetchSpinner = ora2("\u6B63\u5728\u83B7\u53D6 tags...").start();
702
+ exec("git fetch --tags", true);
703
+ fetchSpinner.stop();
704
+ const tags = execOutput("git tag -l --sort=-v:refname").split("\n").filter(Boolean);
705
+ if (tags.length === 0) {
706
+ console.log(colors.yellow("\u6CA1\u6709\u53EF\u4FEE\u6539\u7684 tag"));
707
+ return;
708
+ }
709
+ divider();
710
+ const choices = tags.map((tag) => ({ name: tag, value: tag }));
711
+ choices.push({ name: "\u53D6\u6D88", value: "__cancel__" });
712
+ const tagToUpdate = await select2({
713
+ message: "\u9009\u62E9\u8981\u4FEE\u6539\u7684 tag:",
714
+ choices,
715
+ theme
716
+ });
717
+ if (tagToUpdate === "__cancel__") {
718
+ console.log(colors.yellow("\u5DF2\u53D6\u6D88"));
719
+ return;
720
+ }
721
+ const newMessage = await input2({
722
+ message: "\u8F93\u5165\u65B0\u7684 tag \u6D88\u606F:",
723
+ default: `Release ${tagToUpdate}`,
724
+ theme
725
+ });
726
+ if (!newMessage) {
727
+ console.log(colors.yellow("\u5DF2\u53D6\u6D88"));
728
+ return;
729
+ }
730
+ divider();
731
+ const spinner = ora2(`\u6B63\u5728\u66F4\u65B0 tag: ${tagToUpdate}`).start();
732
+ try {
733
+ execSync3(`git tag -d "${tagToUpdate}"`, { stdio: "pipe" });
734
+ execSync3(`git tag -a "${tagToUpdate}" -m "${newMessage}"`, {
735
+ stdio: "pipe"
736
+ });
737
+ spinner.succeed(`Tag \u5DF2\u66F4\u65B0: ${tagToUpdate}`);
738
+ } catch {
739
+ spinner.fail("tag \u66F4\u65B0\u5931\u8D25");
740
+ return;
741
+ }
742
+ const pushRemote = await select2({
743
+ message: "\u662F\u5426\u63A8\u9001\u5230\u8FDC\u7A0B\uFF08\u4F1A\u5F3A\u5236\u8986\u76D6\uFF09?",
744
+ choices: [
745
+ { name: "\u662F", value: true },
746
+ { name: "\u5426", value: false }
747
+ ],
748
+ theme
749
+ });
750
+ if (pushRemote) {
751
+ const pushSpinner = ora2("\u6B63\u5728\u63A8\u9001\u5230\u8FDC\u7A0B...").start();
752
+ try {
753
+ execSync3(`git push origin "${tagToUpdate}" --force`, { stdio: "pipe" });
754
+ pushSpinner.succeed(`Tag \u5DF2\u63A8\u9001: ${tagToUpdate}`);
755
+ } catch {
756
+ pushSpinner.warn(
757
+ `\u8FDC\u7A0B\u63A8\u9001\u5931\u8D25\uFF0C\u53EF\u7A0D\u540E\u624B\u52A8\u6267\u884C: git push origin ${tagToUpdate} --force`
758
+ );
759
+ }
760
+ }
761
+ }
638
762
 
639
763
  // src/commands/release.ts
640
764
  import { readFileSync as readFileSync2, writeFileSync } from "fs";
@@ -1741,6 +1865,12 @@ Tag \u547D\u4EE4:
1741
1865
  gw tag [prefix] \u4EA4\u4E92\u5F0F\u9009\u62E9\u7248\u672C\u7C7B\u578B\u5E76\u521B\u5EFA tag
1742
1866
  gw t [prefix] \u540C\u4E0A (\u522B\u540D)
1743
1867
 
1868
+ gw tag:delete \u5220\u9664 tag
1869
+ gw td \u540C\u4E0A (\u522B\u540D)
1870
+
1871
+ gw tag:update \u4FEE\u6539 tag \u6D88\u606F
1872
+ gw tu \u540C\u4E0A (\u522B\u540D)
1873
+
1744
1874
  \u53D1\u5E03\u547D\u4EE4:
1745
1875
  gw release \u4EA4\u4E92\u5F0F\u9009\u62E9\u7248\u672C\u53F7\u5E76\u66F4\u65B0 package.json
1746
1876
  gw r \u540C\u4E0A (\u522B\u540D)
@@ -1766,6 +1896,8 @@ Commit \u547D\u4EE4:
1766
1896
  gw d feature/xxx \u76F4\u63A5\u5220\u9664\u6307\u5B9A\u5206\u652F
1767
1897
  gw ts v \u5217\u51FA\u6240\u6709 v \u5F00\u5934\u7684 tag
1768
1898
  gw t \u4EA4\u4E92\u5F0F\u521B\u5EFA tag
1899
+ gw td \u4EA4\u4E92\u5F0F\u5220\u9664 tag
1900
+ gw tu \u4EA4\u4E92\u5F0F\u4FEE\u6539 tag
1769
1901
  gw r \u4EA4\u4E92\u5F0F\u53D1\u5E03\u7248\u672C
1770
1902
  gw s \u4EA4\u4E92\u5F0F\u7BA1\u7406 stash
1771
1903
  gw c \u4EA4\u4E92\u5F0F\u63D0\u4EA4\u4EE3\u7801
@@ -1963,9 +2095,8 @@ process.on("SIGTERM", () => {
1963
2095
  console.log("");
1964
2096
  process.exit(0);
1965
2097
  });
1966
- var version = true ? "0.2.9" : "0.0.0-dev";
2098
+ var version = true ? "0.2.10" : "0.0.0-dev";
1967
2099
  async function mainMenu() {
1968
- await checkForUpdates(version, "@zjex/git-workflow");
1969
2100
  console.log(
1970
2101
  colors.green(`
1971
2102
  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557
@@ -2002,19 +2133,27 @@ async function mainMenu() {
2002
2133
  value: "tag"
2003
2134
  },
2004
2135
  {
2005
- name: `[6] \u{1F4CB} \u5217\u51FA tags ${colors.dim("gw ts")}`,
2136
+ name: `[6] \u{1F5D1}\uFE0F \u5220\u9664 tag ${colors.dim("gw td")}`,
2137
+ value: "tag-delete"
2138
+ },
2139
+ {
2140
+ name: `[7] \u270F\uFE0F \u4FEE\u6539 tag ${colors.dim("gw tu")}`,
2141
+ value: "tag-update"
2142
+ },
2143
+ {
2144
+ name: `[8] \u{1F4CB} \u5217\u51FA tags ${colors.dim("gw ts")}`,
2006
2145
  value: "tags"
2007
2146
  },
2008
2147
  {
2009
- name: `[7] \u{1F4E6} \u53D1\u5E03\u7248\u672C ${colors.dim("gw r")}`,
2148
+ name: `[9] \u{1F4E6} \u53D1\u5E03\u7248\u672C ${colors.dim("gw r")}`,
2010
2149
  value: "release"
2011
2150
  },
2012
2151
  {
2013
- name: `[8] \u{1F4BE} \u7BA1\u7406 stash ${colors.dim("gw s")}`,
2152
+ name: `[a] \u{1F4BE} \u7BA1\u7406 stash ${colors.dim("gw s")}`,
2014
2153
  value: "stash"
2015
2154
  },
2016
2155
  {
2017
- name: `[9] \u2699\uFE0F \u521D\u59CB\u5316\u914D\u7F6E ${colors.dim("gw init")}`,
2156
+ name: `[b] \u2699\uFE0F \u521D\u59CB\u5316\u914D\u7F6E ${colors.dim("gw init")}`,
2018
2157
  value: "init"
2019
2158
  },
2020
2159
  { name: "[0] \u2753 \u5E2E\u52A9", value: "help" },
@@ -2040,6 +2179,14 @@ async function mainMenu() {
2040
2179
  checkGitRepo();
2041
2180
  await createTag();
2042
2181
  break;
2182
+ case "tag-delete":
2183
+ checkGitRepo();
2184
+ await deleteTag();
2185
+ break;
2186
+ case "tag-update":
2187
+ checkGitRepo();
2188
+ await updateTag();
2189
+ break;
2043
2190
  case "tags":
2044
2191
  checkGitRepo();
2045
2192
  await listTags();
@@ -2066,40 +2213,60 @@ async function mainMenu() {
2066
2213
  }
2067
2214
  }
2068
2215
  var cli = cac("gw");
2069
- cli.command("", "\u663E\u793A\u4EA4\u4E92\u5F0F\u83DC\u5355").action(() => {
2216
+ cli.command("", "\u663E\u793A\u4EA4\u4E92\u5F0F\u83DC\u5355").action(async () => {
2217
+ await checkForUpdates(version, "@zjex/git-workflow");
2070
2218
  return mainMenu();
2071
2219
  });
2072
- cli.command("feature", "\u521B\u5EFA feature \u5206\u652F").alias("feat").alias("f").option("--base <branch>", "\u6307\u5B9A\u57FA\u7840\u5206\u652F").action((options) => {
2220
+ cli.command("feature", "\u521B\u5EFA feature \u5206\u652F").alias("feat").alias("f").option("--base <branch>", "\u6307\u5B9A\u57FA\u7840\u5206\u652F").action(async (options) => {
2221
+ await checkForUpdates(version, "@zjex/git-workflow");
2073
2222
  checkGitRepo();
2074
2223
  return createBranch("feature", options.base);
2075
2224
  });
2076
- cli.command("hotfix", "\u521B\u5EFA hotfix \u5206\u652F").alias("fix").alias("h").option("--base <branch>", "\u6307\u5B9A\u57FA\u7840\u5206\u652F").action((options) => {
2225
+ cli.command("hotfix", "\u521B\u5EFA hotfix \u5206\u652F").alias("fix").alias("h").option("--base <branch>", "\u6307\u5B9A\u57FA\u7840\u5206\u652F").action(async (options) => {
2226
+ await checkForUpdates(version, "@zjex/git-workflow");
2077
2227
  checkGitRepo();
2078
2228
  return createBranch("hotfix", options.base);
2079
2229
  });
2080
- cli.command("delete [branch]", "\u5220\u9664\u672C\u5730/\u8FDC\u7A0B\u5206\u652F").alias("del").alias("d").action((branch) => {
2230
+ cli.command("delete [branch]", "\u5220\u9664\u672C\u5730/\u8FDC\u7A0B\u5206\u652F").alias("del").alias("d").action(async (branch) => {
2231
+ await checkForUpdates(version, "@zjex/git-workflow");
2081
2232
  checkGitRepo();
2082
2233
  return deleteBranch(branch);
2083
2234
  });
2084
- cli.command("tags [prefix]", "\u5217\u51FA\u6240\u6709 tag\uFF0C\u53EF\u6309\u524D\u7F00\u8FC7\u6EE4").alias("ts").action((prefix) => {
2235
+ cli.command("tags [prefix]", "\u5217\u51FA\u6240\u6709 tag\uFF0C\u53EF\u6309\u524D\u7F00\u8FC7\u6EE4").alias("ts").action(async (prefix) => {
2236
+ await checkForUpdates(version, "@zjex/git-workflow");
2085
2237
  checkGitRepo();
2086
2238
  return listTags(prefix);
2087
2239
  });
2088
- cli.command("tag [prefix]", "\u4EA4\u4E92\u5F0F\u9009\u62E9\u7248\u672C\u7C7B\u578B\u5E76\u521B\u5EFA tag").alias("t").action((prefix) => {
2240
+ cli.command("tag [prefix]", "\u4EA4\u4E92\u5F0F\u9009\u62E9\u7248\u672C\u7C7B\u578B\u5E76\u521B\u5EFA tag").alias("t").action(async (prefix) => {
2241
+ await checkForUpdates(version, "@zjex/git-workflow");
2089
2242
  checkGitRepo();
2090
2243
  return createTag(prefix);
2091
2244
  });
2092
- cli.command("release", "\u4EA4\u4E92\u5F0F\u9009\u62E9\u7248\u672C\u53F7\u5E76\u66F4\u65B0 package.json").alias("r").action(() => {
2245
+ cli.command("tag:delete", "\u5220\u9664 tag").alias("td").action(async () => {
2246
+ await checkForUpdates(version, "@zjex/git-workflow");
2247
+ checkGitRepo();
2248
+ return deleteTag();
2249
+ });
2250
+ cli.command("tag:update", "\u4FEE\u6539 tag \u6D88\u606F").alias("tu").action(async () => {
2251
+ await checkForUpdates(version, "@zjex/git-workflow");
2252
+ checkGitRepo();
2253
+ return updateTag();
2254
+ });
2255
+ cli.command("release", "\u4EA4\u4E92\u5F0F\u9009\u62E9\u7248\u672C\u53F7\u5E76\u66F4\u65B0 package.json").alias("r").action(async () => {
2256
+ await checkForUpdates(version, "@zjex/git-workflow");
2093
2257
  return release();
2094
2258
  });
2095
- cli.command("init", "\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6 .gwrc.json").action(() => {
2259
+ cli.command("init", "\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6 .gwrc.json").action(async () => {
2260
+ await checkForUpdates(version, "@zjex/git-workflow");
2096
2261
  return init();
2097
2262
  });
2098
- cli.command("stash", "\u4EA4\u4E92\u5F0F\u7BA1\u7406 stash").alias("s").alias("st").action(() => {
2263
+ cli.command("stash", "\u4EA4\u4E92\u5F0F\u7BA1\u7406 stash").alias("s").alias("st").action(async () => {
2264
+ await checkForUpdates(version, "@zjex/git-workflow");
2099
2265
  checkGitRepo();
2100
2266
  return stash();
2101
2267
  });
2102
- cli.command("commit", "\u4EA4\u4E92\u5F0F\u63D0\u4EA4 (Conventional Commits + Gitmoji)").alias("c").alias("cm").action(() => {
2268
+ cli.command("commit", "\u4EA4\u4E92\u5F0F\u63D0\u4EA4 (Conventional Commits + Gitmoji)").alias("c").alias("cm").action(async () => {
2269
+ await checkForUpdates(version, "@zjex/git-workflow");
2103
2270
  checkGitRepo();
2104
2271
  return commit();
2105
2272
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zjex/git-workflow",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "🚀 极简的 Git 工作流 CLI 工具,让分支管理和版本发布变得轻松愉快",
5
5
  "type": "module",
6
6
  "bin": {
@@ -52,4 +52,4 @@
52
52
  "tsx": "^4.21.0",
53
53
  "typescript": "^5.9.3"
54
54
  }
55
- }
55
+ }
@@ -115,7 +115,14 @@ fi
115
115
  CURRENT_VERSION=$(node -p "require('./package.json').version")
116
116
 
117
117
  # [5] 交互式选择版本号
118
- run_step_interactive "5" "选择新版本号" "npm run version"
118
+ echo -e "${BLUE}[5/${TOTAL_STEPS}]${NC} 选择新版本号..."
119
+ echo ""
120
+
121
+ # 记录当前光标位置
122
+ tput sc
123
+
124
+ # 执行版本选择
125
+ npm run version
119
126
 
120
127
  # 获取新版本
121
128
  NEW_VERSION=$(node -p "require('./package.json').version")
@@ -125,8 +132,12 @@ if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then
125
132
  exit 0
126
133
  fi
127
134
 
128
- # 显示版本升级信息
129
- echo -e "${GREEN} ✅${NC} ${DIM}(${CURRENT_VERSION} → ${NEW_VERSION})${NC}"
135
+ # 恢复光标位置并清除后续内容
136
+ tput rc
137
+ tput ed
138
+
139
+ # 显示步骤5完成,带版本信息
140
+ echo -e "${BLUE}[5/${TOTAL_STEPS}]${NC} 选择新版本号... ${GREEN}✅${NC} ${DIM}(${CURRENT_VERSION} → ${NEW_VERSION})${NC}"
130
141
 
131
142
  # [6] 构建项目
132
143
  if ! run_step "6" "构建项目" "npm run build"; then
@@ -22,6 +22,12 @@ Tag 命令:
22
22
  gw tag [prefix] 交互式选择版本类型并创建 tag
23
23
  gw t [prefix] 同上 (别名)
24
24
 
25
+ gw tag:delete 删除 tag
26
+ gw td 同上 (别名)
27
+
28
+ gw tag:update 修改 tag 消息
29
+ gw tu 同上 (别名)
30
+
25
31
  发布命令:
26
32
  gw release 交互式选择版本号并更新 package.json
27
33
  gw r 同上 (别名)
@@ -47,6 +53,8 @@ Commit 命令:
47
53
  gw d feature/xxx 直接删除指定分支
48
54
  gw ts v 列出所有 v 开头的 tag
49
55
  gw t 交互式创建 tag
56
+ gw td 交互式删除 tag
57
+ gw tu 交互式修改 tag
50
58
  gw r 交互式发布版本
51
59
  gw s 交互式管理 stash
52
60
  gw c 交互式提交代码
@@ -334,3 +334,167 @@ function doCreateTag(tagName: string): void {
334
334
  );
335
335
  }
336
336
  }
337
+
338
+ /**
339
+ * 删除 tag
340
+ */
341
+ export async function deleteTag(): Promise<void> {
342
+ const fetchSpinner = ora("正在获取 tags...").start();
343
+ exec("git fetch --tags", true);
344
+ fetchSpinner.stop();
345
+
346
+ const tags = execOutput("git tag -l --sort=-v:refname")
347
+ .split("\n")
348
+ .filter(Boolean);
349
+
350
+ if (tags.length === 0) {
351
+ console.log(colors.yellow("没有可删除的 tag"));
352
+ return;
353
+ }
354
+
355
+ divider();
356
+
357
+ const choices = tags.map((tag) => ({ name: tag, value: tag }));
358
+ choices.push({ name: "取消", value: "__cancel__" });
359
+
360
+ const tagToDelete = await select({
361
+ message: "选择要删除的 tag:",
362
+ choices,
363
+ theme,
364
+ });
365
+
366
+ if (tagToDelete === "__cancel__") {
367
+ console.log(colors.yellow("已取消"));
368
+ return;
369
+ }
370
+
371
+ const confirm = await select({
372
+ message: `确认删除 tag: ${colors.red(tagToDelete)}?`,
373
+ choices: [
374
+ { name: "是", value: true },
375
+ { name: "否", value: false },
376
+ ],
377
+ theme,
378
+ });
379
+
380
+ if (!confirm) {
381
+ console.log(colors.yellow("已取消"));
382
+ return;
383
+ }
384
+
385
+ divider();
386
+
387
+ const spinner = ora(`正在删除本地 tag: ${tagToDelete}`).start();
388
+
389
+ try {
390
+ execSync(`git tag -d "${tagToDelete}"`, { stdio: "pipe" });
391
+ spinner.succeed(`本地 tag 已删除: ${tagToDelete}`);
392
+ } catch {
393
+ spinner.fail("本地 tag 删除失败");
394
+ return;
395
+ }
396
+
397
+ const deleteRemote = await select({
398
+ message: "是否同时删除远程 tag?",
399
+ choices: [
400
+ { name: "是", value: true },
401
+ { name: "否", value: false },
402
+ ],
403
+ theme,
404
+ });
405
+
406
+ if (deleteRemote) {
407
+ const pushSpinner = ora("正在删除远程 tag...").start();
408
+ try {
409
+ execSync(`git push origin --delete "${tagToDelete}"`, { stdio: "pipe" });
410
+ pushSpinner.succeed(`远程 tag 已删除: ${tagToDelete}`);
411
+ } catch {
412
+ pushSpinner.warn(
413
+ `远程删除失败,可稍后手动执行: git push origin --delete ${tagToDelete}`
414
+ );
415
+ }
416
+ }
417
+ }
418
+
419
+ /**
420
+ * 修改 tag(重新打标签)
421
+ */
422
+ export async function updateTag(): Promise<void> {
423
+ const fetchSpinner = ora("正在获取 tags...").start();
424
+ exec("git fetch --tags", true);
425
+ fetchSpinner.stop();
426
+
427
+ const tags = execOutput("git tag -l --sort=-v:refname")
428
+ .split("\n")
429
+ .filter(Boolean);
430
+
431
+ if (tags.length === 0) {
432
+ console.log(colors.yellow("没有可修改的 tag"));
433
+ return;
434
+ }
435
+
436
+ divider();
437
+
438
+ const choices = tags.map((tag) => ({ name: tag, value: tag }));
439
+ choices.push({ name: "取消", value: "__cancel__" });
440
+
441
+ const tagToUpdate = await select({
442
+ message: "选择要修改的 tag:",
443
+ choices,
444
+ theme,
445
+ });
446
+
447
+ if (tagToUpdate === "__cancel__") {
448
+ console.log(colors.yellow("已取消"));
449
+ return;
450
+ }
451
+
452
+ const newMessage = await input({
453
+ message: "输入新的 tag 消息:",
454
+ default: `Release ${tagToUpdate}`,
455
+ theme,
456
+ });
457
+
458
+ if (!newMessage) {
459
+ console.log(colors.yellow("已取消"));
460
+ return;
461
+ }
462
+
463
+ divider();
464
+
465
+ const spinner = ora(`正在更新 tag: ${tagToUpdate}`).start();
466
+
467
+ try {
468
+ // 删除旧 tag
469
+ execSync(`git tag -d "${tagToUpdate}"`, { stdio: "pipe" });
470
+ // 创建新 tag(在同一个 commit 上)
471
+ execSync(`git tag -a "${tagToUpdate}" -m "${newMessage}"`, {
472
+ stdio: "pipe",
473
+ });
474
+ spinner.succeed(`Tag 已更新: ${tagToUpdate}`);
475
+ } catch {
476
+ spinner.fail("tag 更新失败");
477
+ return;
478
+ }
479
+
480
+ const pushRemote = await select({
481
+ message: "是否推送到远程(会强制覆盖)?",
482
+ choices: [
483
+ { name: "是", value: true },
484
+ { name: "否", value: false },
485
+ ],
486
+ theme,
487
+ });
488
+
489
+ if (pushRemote) {
490
+ const pushSpinner = ora("正在推送到远程...").start();
491
+ try {
492
+ execSync(`git push origin "${tagToUpdate}" --force`, { stdio: "pipe" });
493
+ pushSpinner.succeed(`Tag 已推送: ${tagToUpdate}`);
494
+ } catch {
495
+ pushSpinner.warn(
496
+ `远程推送失败,可稍后手动执行: git push origin ${tagToUpdate} --force`
497
+ );
498
+ }
499
+ }
500
+ }
package/src/index.ts CHANGED
@@ -5,7 +5,7 @@ import { select } from "@inquirer/prompts";
5
5
  import { ExitPromptError } from "@inquirer/core";
6
6
  import { checkGitRepo, theme, colors } from "./utils.js";
7
7
  import { createBranch, deleteBranch } from "./commands/branch.js";
8
- import { listTags, createTag } from "./commands/tag.js";
8
+ import { listTags, createTag, deleteTag, updateTag } from "./commands/tag.js";
9
9
  import { release } from "./commands/release.js";
10
10
  import { init } from "./commands/init.js";
11
11
  import { stash } from "./commands/stash.js";
@@ -55,9 +55,6 @@ const version: string =
55
55
 
56
56
  // 交互式主菜单
57
57
  async function mainMenu(): Promise<void> {
58
- // 先检查更新,等待完成后再显示主菜单
59
- await checkForUpdates(version, "@zjex/git-workflow");
60
-
61
58
  // ASCII Art Logo
62
59
  console.log(
63
60
  colors.green(`
@@ -95,19 +92,27 @@ async function mainMenu(): Promise<void> {
95
92
  value: "tag",
96
93
  },
97
94
  {
98
- name: `[6] 📋 列出 tags ${colors.dim("gw ts")}`,
95
+ name: `[6] 🗑️ 删除 tag ${colors.dim("gw td")}`,
96
+ value: "tag-delete",
97
+ },
98
+ {
99
+ name: `[7] ✏️ 修改 tag ${colors.dim("gw tu")}`,
100
+ value: "tag-update",
101
+ },
102
+ {
103
+ name: `[8] 📋 列出 tags ${colors.dim("gw ts")}`,
99
104
  value: "tags",
100
105
  },
101
106
  {
102
- name: `[7] 📦 发布版本 ${colors.dim("gw r")}`,
107
+ name: `[9] 📦 发布版本 ${colors.dim("gw r")}`,
103
108
  value: "release",
104
109
  },
105
110
  {
106
- name: `[8] 💾 管理 stash ${colors.dim("gw s")}`,
111
+ name: `[a] 💾 管理 stash ${colors.dim("gw s")}`,
107
112
  value: "stash",
108
113
  },
109
114
  {
110
- name: `[9] ⚙️ 初始化配置 ${colors.dim("gw init")}`,
115
+ name: `[b] ⚙️ 初始化配置 ${colors.dim("gw init")}`,
111
116
  value: "init",
112
117
  },
113
118
  { name: "[0] ❓ 帮助", value: "help" },
@@ -134,6 +139,14 @@ async function mainMenu(): Promise<void> {
134
139
  checkGitRepo();
135
140
  await createTag();
136
141
  break;
142
+ case "tag-delete":
143
+ checkGitRepo();
144
+ await deleteTag();
145
+ break;
146
+ case "tag-update":
147
+ checkGitRepo();
148
+ await updateTag();
149
+ break;
137
150
  case "tags":
138
151
  checkGitRepo();
139
152
  await listTags();
@@ -163,7 +176,8 @@ async function mainMenu(): Promise<void> {
163
176
  const cli = cac("gw");
164
177
 
165
178
  // 默认命令 - 显示交互式菜单
166
- cli.command("", "显示交互式菜单").action(() => {
179
+ cli.command("", "显示交互式菜单").action(async () => {
180
+ await checkForUpdates(version, "@zjex/git-workflow");
167
181
  return mainMenu();
168
182
  });
169
183
 
@@ -172,7 +186,8 @@ cli
172
186
  .alias("feat")
173
187
  .alias("f")
174
188
  .option("--base <branch>", "指定基础分支")
175
- .action((options: { base?: string }) => {
189
+ .action(async (options: { base?: string }) => {
190
+ await checkForUpdates(version, "@zjex/git-workflow");
176
191
  checkGitRepo();
177
192
  return createBranch("feature", options.base);
178
193
  });
@@ -182,7 +197,8 @@ cli
182
197
  .alias("fix")
183
198
  .alias("h")
184
199
  .option("--base <branch>", "指定基础分支")
185
- .action((options: { base?: string }) => {
200
+ .action(async (options: { base?: string }) => {
201
+ await checkForUpdates(version, "@zjex/git-workflow");
186
202
  checkGitRepo();
187
203
  return createBranch("hotfix", options.base);
188
204
  });
@@ -191,7 +207,8 @@ cli
191
207
  .command("delete [branch]", "删除本地/远程分支")
192
208
  .alias("del")
193
209
  .alias("d")
194
- .action((branch?: string) => {
210
+ .action(async (branch?: string) => {
211
+ await checkForUpdates(version, "@zjex/git-workflow");
195
212
  checkGitRepo();
196
213
  return deleteBranch(branch);
197
214
  });
@@ -199,7 +216,8 @@ cli
199
216
  cli
200
217
  .command("tags [prefix]", "列出所有 tag,可按前缀过滤")
201
218
  .alias("ts")
202
- .action((prefix?: string) => {
219
+ .action(async (prefix?: string) => {
220
+ await checkForUpdates(version, "@zjex/git-workflow");
203
221
  checkGitRepo();
204
222
  return listTags(prefix);
205
223
  });
@@ -207,19 +225,40 @@ cli
207
225
  cli
208
226
  .command("tag [prefix]", "交互式选择版本类型并创建 tag")
209
227
  .alias("t")
210
- .action((prefix?: string) => {
228
+ .action(async (prefix?: string) => {
229
+ await checkForUpdates(version, "@zjex/git-workflow");
211
230
  checkGitRepo();
212
231
  return createTag(prefix);
213
232
  });
214
233
 
234
+ cli
235
+ .command("tag:delete", "删除 tag")
236
+ .alias("td")
237
+ .action(async () => {
238
+ await checkForUpdates(version, "@zjex/git-workflow");
239
+ checkGitRepo();
240
+ return deleteTag();
241
+ });
242
+
243
+ cli
244
+ .command("tag:update", "修改 tag 消息")
245
+ .alias("tu")
246
+ .action(async () => {
247
+ await checkForUpdates(version, "@zjex/git-workflow");
248
+ checkGitRepo();
249
+ return updateTag();
250
+ });
251
+
215
252
  cli
216
253
  .command("release", "交互式选择版本号并更新 package.json")
217
254
  .alias("r")
218
- .action(() => {
255
+ .action(async () => {
256
+ await checkForUpdates(version, "@zjex/git-workflow");
219
257
  return release();
220
258
  });
221
259
 
222
- cli.command("init", "初始化配置文件 .gwrc.json").action(() => {
260
+ cli.command("init", "初始化配置文件 .gwrc.json").action(async () => {
261
+ await checkForUpdates(version, "@zjex/git-workflow");
223
262
  return init();
224
263
  });
225
264
 
@@ -227,7 +266,8 @@ cli
227
266
  .command("stash", "交互式管理 stash")
228
267
  .alias("s")
229
268
  .alias("st")
230
- .action(() => {
269
+ .action(async () => {
270
+ await checkForUpdates(version, "@zjex/git-workflow");
231
271
  checkGitRepo();
232
272
  return stash();
233
273
  });
@@ -236,7 +276,8 @@ cli
236
276
  .command("commit", "交互式提交 (Conventional Commits + Gitmoji)")
237
277
  .alias("c")
238
278
  .alias("cm")
239
- .action(() => {
279
+ .action(async () => {
280
+ await checkForUpdates(version, "@zjex/git-workflow");
240
281
  checkGitRepo();
241
282
  return commit();
242
283
  });
package/zjex.svg ADDED
@@ -0,0 +1 @@
1
+ <svg data-v-0dd9719b="" version="1.0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 340.000000 250.000000" preserveAspectRatio="xMidYMid meet" color-interpolation-filters="sRGB" style="margin: auto;"> <rect data-v-0dd9719b="" x="0" y="0" width="100%" height="100%" fill="#fff" fill-opacity="1" class="background"></rect> <rect data-v-0dd9719b="" x="0" y="0" width="100%" height="100%" fill="url(#watermark)" fill-opacity="1" class="watermarklayer"></rect> <g data-v-0dd9719b="" fill="#333" class="icon-text-wrapper icon-svg-group iconsvg" transform="translate(62.92499542236328,95.46575355529785)"><g class="iconsvg-imagesvg" transform="translate(0,0)"><g><rect fill="#333" fill-opacity="0" stroke-width="2" x="0" y="0" width="60" height="59.06848991405534" class="image-rect"></rect> <svg x="0" y="0" width="60" height="59.06848991405534" filtersec="colorsb2691092612" class="image-svg-svg primary" style="overflow: visible;"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0.4385022521018982 -0.000009216904800268821 101.5615005493164 99.98497772216797"><path d="M69.3 59.41l-9.89 9.89L51 77.73 30.46 98.26A6 6 0 0 1 22 89.83L42.56 69.3 51 60.88l9.9-9.9zM102 24.28a6 6 0 0 1-1.75 4.21L77.72 51l-8.42-8.44 22.5-22.5a6 6 0 0 1 10.2 4.22z" fill="#0059cc"></path><path d="M83.64 6a5.94 5.94 0 0 1-1.74 4.21L41.08 51l-8.42-8.42 9.9-9.89L51 24.24 73.48 1.75A6 6 0 0 1 83.64 6zM32.66 59.41L12.13 79.93a6 6 0 0 1-8.42-8.42L24.24 51z" fill="#00dac7"></path><path d="M51 24.24l-8.42 8.43-22.5-22.5A6 6 0 0 1 24.28 0a5.89 5.89 0 0 1 4.2 1.75zM98.25 79.93a5.94 5.94 0 0 1-8.42 0L51 41.09l8.42-8.42 9.9 9.89 8.4 8.44 20.53 20.51a6 6 0 0 1 0 8.42z" fill="#00baec"></path><path d="M51 60.88l-8.44 8.42L1.74 28.49a6 6 0 0 1 8.43-8.43l22.49 22.5L41.08 51zM79.93 98.26a6 6 0 0 1-8.42 0L51 77.73l8.42-8.43 20.51 20.53a6 6 0 0 1 0 8.43z" fill="#00abd8"></path></svg></svg> <!----></g></g> <g transform="translate(67,0.3792438507080078)"><g data-gra="path-name" fill-rule="" class="tp-name iconsvg-namesvg"><g transform="scale(1)"><g><path d="M36.2-46.02L36.2-46.02 36.2-44.72 13.97-1.5 20.73-1.5Q22.95-1.5 25.19-2.21 27.43-2.93 29.35-4.55 31.27-6.17 32.63-8.87 34-11.57 34.45-15.6L34.45-15.6 35.95-15.6Q35.75-13.39 35.75-9.88L35.75-9.88Q35.75-8.38 35.81-5.66 35.88-2.93 36.2 0L36.2 0Q32.63-0.13 28.11-0.16 23.6-0.2 20.02-0.2L20.02-0.2Q15.79-0.2 11.18-0.16 6.57-0.13 2.54 0L2.54 0 2.54-1.3 24.83-44.52 17.81-44.52Q14.56-44.52 11.83-43.32 9.1-42.12 7.28-39.23 5.46-36.34 4.81-31.2L4.81-31.2 3.31-31.2Q3.45-32.11 3.48-33.41 3.51-34.71 3.51-36.14L3.51-36.14Q3.51-37.63 3.41-40.37 3.31-43.09 3.06-46.02L3.06-46.02Q6.31-45.89 10.37-45.86 14.43-45.83 17.68-45.83L17.68-45.83Q22.04-45.83 26.98-45.86 31.92-45.89 36.2-46.02ZM37.64 12.22L37.64 12.22 37.64 10.92Q40.23 10.66 42.05 9.39 43.88 8.13 44.85 5.07 45.83 2.02 45.83-3.51L45.83-3.51 45.83-39.13Q45.83-41.54 45.47-42.67 45.11-43.81 44.07-44.23 43.03-44.66 40.95-44.72L40.95-44.72 40.95-46.02Q42.58-45.95 45.21-45.89 47.84-45.83 50.77-45.83L50.77-45.83Q53.69-45.83 56.45-45.89 59.22-45.95 61.04-46.02L61.04-46.02 61.04-44.72Q59.02-44.66 57.95-44.23 56.88-43.81 56.52-42.67 56.16-41.54 56.16-39.13L56.16-39.13 56.16-15.34Q56.16-12.68 56.16-9.59 56.16-6.5 55.93-3.58 55.7-0.65 55.06 1.63L55.06 1.63Q53.76 6.11 49.43 9.17 45.11 12.22 37.64 12.22ZM99.78-46.02L99.78-46.02Q99.52-43.16 99.42-40.5 99.32-37.83 99.32-36.4L99.32-36.4Q99.32-35.1 99.39-33.93 99.45-32.76 99.52-31.98L99.52-31.98 98.02-31.98Q97.37-36.73 96.01-39.49 94.64-42.25 92.46-43.39 90.29-44.52 87.36-44.52L87.36-44.52 84.7-44.52Q82.75-44.52 81.8-44.2 80.86-43.88 80.54-42.93 80.21-41.99 80.21-39.91L80.21-39.91 80.21-6.11Q80.21-4.09 80.54-3.12 80.86-2.15 81.8-1.82 82.75-1.5 84.7-1.5L84.7-1.5 87.88-1.5Q90.81-1.5 93.05-2.76 95.29-4.03 96.88-7.08 98.48-10.14 99.32-15.34L99.32-15.34 100.81-15.34Q100.62-13.26 100.62-9.88L100.62-9.88Q100.62-8.38 100.69-5.66 100.75-2.93 101.08 0L101.08 0Q97.76-0.13 93.6-0.16 89.44-0.2 86.19-0.2L86.19-0.2Q83.98-0.2 80.34-0.2 76.7-0.2 72.61-0.16 68.51-0.13 65 0L65 0 65-1.3Q67.08-1.43 68.12-1.82 69.16-2.21 69.52-3.38 69.88-4.55 69.88-6.89L69.88-6.89 69.88-39.13Q69.88-41.54 69.52-42.67 69.16-43.81 68.09-44.23 67.02-44.66 65-44.72L65-44.72 65-46.02Q68.51-45.95 72.61-45.89 76.7-45.83 80.34-45.83 83.98-45.83 86.19-45.83L86.19-45.83Q89.18-45.83 92.98-45.86 96.79-45.89 99.78-46.02ZM78.26-23.79L89.64-23.79Q89.64-23.79 89.64-23.14 89.64-22.49 89.64-22.49L89.64-22.49 78.26-22.49Q78.26-22.49 78.26-23.14 78.26-23.79 78.26-23.79L78.26-23.79ZM90.03-32.37L91.52-32.37Q91.26-28.67 91.29-26.71 91.33-24.77 91.33-23.14L91.33-23.14Q91.33-21.52 91.39-19.57 91.46-17.62 91.72-13.91L91.72-13.91 90.22-13.91Q89.9-16.19 89.02-18.14 88.14-20.09 86.52-21.29 84.89-22.49 82.29-22.49L82.29-22.49 82.29-23.79Q84.89-23.79 86.45-25.22 88.01-26.65 88.86-28.63 89.7-30.62 90.03-32.37L90.03-32.37ZM123.44-46.09L123.44-46.09 123.44-44.72Q120.51-44.72 119.7-44.17 118.89-43.62 119.8-42.25L119.8-42.25 145.53-4.62Q146.84-2.79 147.62-2.15 148.4-1.5 149.69-1.36L149.69-1.36 149.69 0Q148.4-0.07 145.93-0.16 143.45-0.26 140.79-0.26L140.79-0.26Q137.87-0.26 134.84-0.16 131.82-0.07 130.32 0L130.32 0 130.32-1.36Q133.31-1.36 134.19-1.79 135.07-2.21 134.16-3.58L134.16-3.58 108.36-41.47Q107.12-43.36 106.34-44.01 105.56-44.66 104.19-44.72L104.19-44.72 104.19-46.09Q105.56-46.02 108.19-45.92 110.83-45.83 113.49-45.83L113.49-45.83Q116.42-45.83 119.11-45.92 121.81-46.02 123.44-46.09ZM113.75-9.23L124.02-23.14Q124.02-23.14 124.28-22.3 124.54-21.45 124.54-21.45L124.54-21.45 118.04-12.54Q115.44-9.04 115.11-6.6 114.79-4.16 116.25-2.83 117.72-1.5 120.58-1.3L120.58-1.3 120.58 0Q119.34-0.07 117.33-0.1 115.31-0.13 113.36-0.16 111.41-0.2 110.31-0.2L110.31-0.2Q106.41-0.2 104.33 0L104.33 0 104.33-1.3Q106.6-2.08 108.94-4.06 111.28-6.04 113.75-9.23L113.75-9.23ZM146.77-46.02L146.77-46.02 146.77-44.72Q144.63-44.13 142.51-42.25 140.4-40.37 138.58-37.9L138.58-37.9 128.05-23.86Q128.05-23.86 127.82-24.7 127.59-25.55 127.59-25.55L127.59-25.55 134.29-34.58Q138-39.33 137.28-41.93 136.56-44.52 132.6-44.72L132.6-44.72 132.6-46.02Q134.49-45.95 136.82-45.89 139.16-45.83 140.79-45.83L140.79-45.83Q144.69-45.83 146.77-46.02Z" transform="translate(-2.5399999618530273, 46.09000015258789)"></path></g> <!----> <!----> <!----> <!----> <!----> <!----> <!----></g></g> <!----></g></g><defs v-gra="od"></defs></svg>