@zjex/git-workflow 0.3.0 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -59,9 +59,14 @@ var init_utils = __esm({
59
59
  red: (s) => `\x1B[31m${s}\x1B[0m`,
60
60
  green: (s) => `\x1B[32m${s}\x1B[0m`,
61
61
  yellow: (s) => `\x1B[33m${s}\x1B[0m`,
62
+ blue: (s) => `\x1B[34m${s}\x1B[0m`,
62
63
  cyan: (s) => `\x1B[36m${s}\x1B[0m`,
63
64
  dim: (s) => `\x1B[2m${s}\x1B[0m`,
64
65
  bold: (s) => `\x1B[1m${s}\x1B[0m`,
66
+ purple: (s) => `\x1B[35m${s}\x1B[0m`,
67
+ orange: (s) => `\x1B[38;5;208m${s}\x1B[0m`,
68
+ lightPurple: (s) => `\x1B[38;5;141m${s}\x1B[0m`,
69
+ white: (s) => `\x1B[37m${s}\x1B[0m`,
65
70
  reset: "\x1B[0m"
66
71
  };
67
72
  TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10).replace(/-/g, "");
@@ -655,7 +660,8 @@ async function listTags(prefix) {
655
660
  exec("git fetch --tags", true);
656
661
  spinner.stop();
657
662
  const pattern = prefix ? `${prefix}*` : "";
658
- const tags = execOutput(`git tag -l ${pattern} --sort=v:refname`).split("\n").filter(Boolean);
663
+ const allTags = execOutput(`git tag -l ${pattern} --sort=v:refname`).split("\n").filter(Boolean);
664
+ const tags = allTags.filter((tag) => /\d/.test(tag));
659
665
  if (tags.length === 0) {
660
666
  console.log(
661
667
  colors.yellow(prefix ? `\u6CA1\u6709 '${prefix}' \u5F00\u5934\u7684 tag` : "\u6CA1\u6709 tag")
@@ -674,7 +680,7 @@ async function listTags(prefix) {
674
680
  }
675
681
  const grouped = /* @__PURE__ */ new Map();
676
682
  tags.forEach((tag) => {
677
- const prefix2 = tag.replace(/[0-9].*/, "") || "(\u65E0\u524D\u7F00)";
683
+ const prefix2 = tag.replace(/\d.*/, "") || "(\u65E0\u524D\u7F00)";
678
684
  if (!grouped.has(prefix2)) {
679
685
  grouped.set(prefix2, []);
680
686
  }
@@ -730,7 +736,7 @@ async function listTags(prefix) {
730
736
  }
731
737
  }
732
738
  function getLatestTag(prefix) {
733
- const tags = execOutput(`git tag -l "${prefix}*" --sort=-v:refname`).split("\n").filter(Boolean);
739
+ const tags = execOutput(`git tag -l "${prefix}*" --sort=-v:refname`).split("\n").filter((tag) => tag && /\d/.test(tag));
734
740
  return tags[0] || "";
735
741
  }
736
742
  async function createTag(inputPrefix) {
@@ -745,7 +751,7 @@ async function createTag(inputPrefix) {
745
751
  console.log(colors.dim(`(\u4F7F\u7528\u914D\u7F6E\u7684\u9ED8\u8BA4\u524D\u7F00: ${prefix})`));
746
752
  }
747
753
  if (!prefix) {
748
- const allTags = execOutput("git tag -l").split("\n").filter(Boolean);
754
+ const allTags = execOutput("git tag -l").split("\n").filter((tag) => tag && /\d/.test(tag));
749
755
  if (allTags.length === 0) {
750
756
  prefix = await input2({
751
757
  message: "\u5F53\u524D\u4ED3\u5E93\u6CA1\u6709 tag\uFF0C\u8BF7\u8F93\u5165\u524D\u7F00 (\u5982 v):",
@@ -792,7 +798,7 @@ async function createTag(inputPrefix) {
792
798
  return;
793
799
  }
794
800
  const prefixes = [
795
- ...new Set(allTags.map((t) => t.replace(/[0-9].*/, "")).filter(Boolean))
801
+ ...new Set(allTags.map((t) => t.replace(/\d.*/, "")).filter(Boolean))
796
802
  ];
797
803
  if (prefixes.length === 0) {
798
804
  prefix = await input2({
@@ -1458,12 +1464,34 @@ async function init() {
1458
1464
  ],
1459
1465
  theme
1460
1466
  });
1467
+ const aiUseEmoji = await select4({
1468
+ message: "AI \u751F\u6210\u7684 commit message \u662F\u5426\u5305\u542B emoji?",
1469
+ choices: [
1470
+ {
1471
+ name: "\u662F\uFF08\u63A8\u8350\uFF09",
1472
+ value: true,
1473
+ description: "\u5982\uFF1A\u2728 feat(auth): \u6DFB\u52A0\u7528\u6237\u767B\u5F55\u529F\u80FD"
1474
+ },
1475
+ {
1476
+ name: "\u5426",
1477
+ value: false,
1478
+ description: "\u5982\uFF1Afeat(auth): \u6DFB\u52A0\u7528\u6237\u767B\u5F55\u529F\u80FD"
1479
+ },
1480
+ {
1481
+ name: "\u8DDF\u968F\u5168\u5C40\u8BBE\u7F6E",
1482
+ value: void 0,
1483
+ description: `\u5F53\u524D\u5168\u5C40\u8BBE\u7F6E\uFF1A${useEmoji ? "\u542F\u7528" : "\u7981\u7528"} emoji`
1484
+ }
1485
+ ],
1486
+ theme
1487
+ });
1461
1488
  config2.aiCommit = {
1462
1489
  enabled: true,
1463
1490
  provider: aiProvider,
1464
1491
  apiKey: apiKey || void 0,
1465
1492
  language,
1466
- detailedDescription
1493
+ detailedDescription,
1494
+ useEmoji: aiUseEmoji
1467
1495
  };
1468
1496
  const defaultModels = {
1469
1497
  github: "gpt-4o-mini",
@@ -1807,13 +1835,13 @@ function getGitDiff() {
1807
1835
  return "";
1808
1836
  }
1809
1837
  }
1810
- function buildPrompt(diff, language, detailedDescription = false) {
1838
+ function buildPrompt(diff, language, detailedDescription = false, useEmoji = true) {
1811
1839
  const isZh = language === "zh-CN";
1812
1840
  if (detailedDescription) {
1813
1841
  const systemPrompt = isZh ? `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684 Git commit message \u751F\u6210\u52A9\u624B\u3002\u8BF7\u6839\u636E\u63D0\u4F9B\u7684 git diff \u751F\u6210\u7B26\u5408 Conventional Commits \u89C4\u8303\u7684\u8BE6\u7EC6 commit message\u3002
1814
1842
 
1815
1843
  \u683C\u5F0F\u8981\u6C42\uFF1A
1816
- 1. \u7B2C\u4E00\u884C\uFF1A<type>(<scope>): <subject>
1844
+ 1. \u7B2C\u4E00\u884C\uFF1A${useEmoji ? "<emoji> " : ""}<type>(<scope>): <subject>
1817
1845
  2. \u7A7A\u884C
1818
1846
  3. \u8BE6\u7EC6\u63CF\u8FF0\uFF1A\u5217\u51FA\u4E3B\u8981\u4FEE\u6539\u70B9\uFF0C\u6BCF\u4E2A\u4FEE\u6539\u70B9\u4E00\u884C\uFF0C\u4EE5 "- " \u5F00\u5934
1819
1847
 
@@ -1824,9 +1852,22 @@ function buildPrompt(diff, language, detailedDescription = false) {
1824
1852
  - \u8BE6\u7EC6\u63CF\u8FF0\u8981\u5217\u51FA 3-6 \u4E2A\u4E3B\u8981\u4FEE\u6539\u70B9\uFF0C\u6BCF\u4E2A\u4FEE\u6539\u70B9\u7B80\u6D01\u660E\u4E86
1825
1853
  - \u5982\u679C\u4FEE\u6539\u8F83\u5C11\uFF0C\u53EF\u4EE5\u53EA\u5217\u51FA 2-3 \u4E2A\u4FEE\u6539\u70B9
1826
1854
  - \u4E0D\u8981\u6709\u5176\u4ED6\u89E3\u91CA\u6216\u591A\u4F59\u5185\u5BB9
1855
+ ${useEmoji ? `
1856
+ Emoji \u6620\u5C04\u89C4\u5219\uFF1A
1857
+ - feat: \u2728 (\u65B0\u529F\u80FD)
1858
+ - fix: \u{1F41B} (\u4FEE\u590DBug)
1859
+ - docs: \u{1F4DD} (\u6587\u6863)
1860
+ - style: \u{1F484} (\u4EE3\u7801\u683C\u5F0F)
1861
+ - refactor: \u267B\uFE0F (\u91CD\u6784)
1862
+ - perf: \u26A1\uFE0F (\u6027\u80FD\u4F18\u5316)
1863
+ - test: \u2705 (\u6D4B\u8BD5)
1864
+ - build: \u{1F4E6} (\u6784\u5EFA)
1865
+ - ci: \u{1F477} (CI/CD)
1866
+ - chore: \u{1F527} (\u5176\u4ED6\u6742\u9879)
1867
+ - revert: \u23EA (\u56DE\u6EDA)` : ""}
1827
1868
 
1828
1869
  \u793A\u4F8B\uFF1A
1829
- feat(auth): \u6DFB\u52A0\u7528\u6237\u767B\u5F55\u529F\u80FD
1870
+ ${useEmoji ? "\u2728 " : ""}feat(auth): \u6DFB\u52A0\u7528\u6237\u767B\u5F55\u529F\u80FD
1830
1871
 
1831
1872
  - \u5B9E\u73B0\u7528\u6237\u540D\u5BC6\u7801\u767B\u5F55\u63A5\u53E3
1832
1873
  - \u6DFB\u52A0\u767B\u5F55\u72B6\u6001\u9A8C\u8BC1\u4E2D\u95F4\u4EF6
@@ -1834,7 +1875,7 @@ feat(auth): \u6DFB\u52A0\u7528\u6237\u767B\u5F55\u529F\u80FD
1834
1875
  - \u66F4\u65B0\u7528\u6237\u8BA4\u8BC1\u76F8\u5173\u6587\u6863` : `You are a professional Git commit message generator. Generate a detailed commit message following Conventional Commits specification based on the provided git diff.
1835
1876
 
1836
1877
  Format requirements:
1837
- 1. First line: <type>(<scope>): <subject>
1878
+ 1. First line: ${useEmoji ? "<emoji> " : ""}<type>(<scope>): <subject>
1838
1879
  2. Empty line
1839
1880
  3. Detailed description: List main changes, one per line, starting with "- "
1840
1881
 
@@ -1845,9 +1886,22 @@ Rules:
1845
1886
  - Detailed description should list 3-6 main changes, each change should be concise
1846
1887
  - If changes are minimal, list 2-3 changes
1847
1888
  - No explanations or extra content
1889
+ ${useEmoji ? `
1890
+ Emoji mapping rules:
1891
+ - feat: \u2728 (new feature)
1892
+ - fix: \u{1F41B} (bug fix)
1893
+ - docs: \u{1F4DD} (documentation)
1894
+ - style: \u{1F484} (code style)
1895
+ - refactor: \u267B\uFE0F (refactoring)
1896
+ - perf: \u26A1\uFE0F (performance)
1897
+ - test: \u2705 (testing)
1898
+ - build: \u{1F4E6} (build)
1899
+ - ci: \u{1F477} (CI/CD)
1900
+ - chore: \u{1F527} (chore)
1901
+ - revert: \u23EA (revert)` : ""}
1848
1902
 
1849
1903
  Example:
1850
- feat(auth): add user login functionality
1904
+ ${useEmoji ? "\u2728 " : ""}feat(auth): add user login functionality
1851
1905
 
1852
1906
  - Implement username/password login API
1853
1907
  - Add login status validation middleware
@@ -1865,30 +1919,56 @@ ${userPrompt}`;
1865
1919
  const systemPrompt = isZh ? `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684 Git commit message \u751F\u6210\u52A9\u624B\u3002\u8BF7\u6839\u636E\u63D0\u4F9B\u7684 git diff \u751F\u6210\u7B26\u5408 Conventional Commits \u89C4\u8303\u7684 commit message\u3002
1866
1920
 
1867
1921
  \u89C4\u5219\uFF1A
1868
- 1. \u683C\u5F0F\uFF1A<type>(<scope>): <subject>
1922
+ 1. \u683C\u5F0F\uFF1A${useEmoji ? "<emoji> " : ""}<type>(<scope>): <subject>
1869
1923
  2. type \u5FC5\u987B\u662F\u4EE5\u4E0B\u4E4B\u4E00\uFF1Afeat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
1870
1924
  3. scope \u662F\u53EF\u9009\u7684\uFF0C\u8868\u793A\u5F71\u54CD\u8303\u56F4
1871
1925
  4. subject \u7528\u4E2D\u6587\u63CF\u8FF0\uFF0C\u7B80\u6D01\u660E\u4E86\uFF0C\u4E0D\u8D85\u8FC7 50 \u5B57
1872
1926
  5. \u53EA\u8FD4\u56DE\u4E00\u6761 commit message\uFF0C\u5373\u4F7F\u6709\u591A\u4E2A\u6587\u4EF6\u6539\u52A8\u4E5F\u8981\u603B\u7ED3\u6210\u4E00\u6761
1873
1927
  6. \u4E0D\u8981\u6709\u5176\u4ED6\u89E3\u91CA\u6216\u591A\u4F59\u5185\u5BB9
1928
+ ${useEmoji ? `
1929
+ Emoji \u6620\u5C04\u89C4\u5219\uFF1A
1930
+ - feat: \u2728 (\u65B0\u529F\u80FD)
1931
+ - fix: \u{1F41B} (\u4FEE\u590DBug)
1932
+ - docs: \u{1F4DD} (\u6587\u6863)
1933
+ - style: \u{1F484} (\u4EE3\u7801\u683C\u5F0F)
1934
+ - refactor: \u267B\uFE0F (\u91CD\u6784)
1935
+ - perf: \u26A1\uFE0F (\u6027\u80FD\u4F18\u5316)
1936
+ - test: \u2705 (\u6D4B\u8BD5)
1937
+ - build: \u{1F4E6} (\u6784\u5EFA)
1938
+ - ci: \u{1F477} (CI/CD)
1939
+ - chore: \u{1F527} (\u5176\u4ED6\u6742\u9879)
1940
+ - revert: \u23EA (\u56DE\u6EDA)` : ""}
1874
1941
 
1875
1942
  \u793A\u4F8B\uFF1A
1876
- - feat(auth): \u6DFB\u52A0\u7528\u6237\u767B\u5F55\u529F\u80FD
1877
- - fix(api): \u4FEE\u590D\u6570\u636E\u83B7\u53D6\u5931\u8D25\u7684\u95EE\u9898
1878
- - docs(readme): \u66F4\u65B0\u5B89\u88C5\u8BF4\u660E` : `You are a professional Git commit message generator. Generate a commit message following Conventional Commits specification based on the provided git diff.
1943
+ - ${useEmoji ? "\u2728 " : ""}feat(auth): \u6DFB\u52A0\u7528\u6237\u767B\u5F55\u529F\u80FD
1944
+ - ${useEmoji ? "\u{1F41B} " : ""}fix(api): \u4FEE\u590D\u6570\u636E\u83B7\u53D6\u5931\u8D25\u7684\u95EE\u9898
1945
+ - ${useEmoji ? "\u{1F4DD} " : ""}docs(readme): \u66F4\u65B0\u5B89\u88C5\u8BF4\u660E` : `You are a professional Git commit message generator. Generate a commit message following Conventional Commits specification based on the provided git diff.
1879
1946
 
1880
1947
  Rules:
1881
- 1. Format: <type>(<scope>): <subject>
1948
+ 1. Format: ${useEmoji ? "<emoji> " : ""}<type>(<scope>): <subject>
1882
1949
  2. type must be one of: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
1883
1950
  3. scope is optional, indicates the affected area
1884
1951
  4. subject should be concise, no more than 50 characters
1885
1952
  5. Return only ONE commit message, even if multiple files are changed, summarize into one message
1886
1953
  6. No explanations or extra content
1954
+ ${useEmoji ? `
1955
+ Emoji mapping rules:
1956
+ - feat: \u2728 (new feature)
1957
+ - fix: \u{1F41B} (bug fix)
1958
+ - docs: \u{1F4DD} (documentation)
1959
+ - style: \u{1F484} (code style)
1960
+ - refactor: \u267B\uFE0F (refactoring)
1961
+ - perf: \u26A1\uFE0F (performance)
1962
+ - test: \u2705 (testing)
1963
+ - build: \u{1F4E6} (build)
1964
+ - ci: \u{1F477} (CI/CD)
1965
+ - chore: \u{1F527} (chore)
1966
+ - revert: \u23EA (revert)` : ""}
1887
1967
 
1888
1968
  Examples:
1889
- - feat(auth): add user login functionality
1890
- - fix(api): resolve data fetching failure
1891
- - docs(readme): update installation guide`;
1969
+ - ${useEmoji ? "\u2728 " : ""}feat(auth): add user login functionality
1970
+ - ${useEmoji ? "\u{1F41B} " : ""}fix(api): resolve data fetching failure
1971
+ - ${useEmoji ? "\u{1F4DD} " : ""}docs(readme): update installation guide`;
1892
1972
  const userPrompt = isZh ? `\u8BF7\u6839\u636E\u4EE5\u4E0B git diff \u751F\u6210 commit message\uFF1A
1893
1973
 
1894
1974
  ${diff}` : `Generate a commit message based on the following git diff:
@@ -1993,7 +2073,9 @@ async function callOllamaAPI(prompt, model, maxTokens) {
1993
2073
  }
1994
2074
  }
1995
2075
  function cleanAIResponse(response) {
1996
- const lines = response.split("\n").map((line) => line.trim()).filter((line) => line);
2076
+ let cleaned = response.replace(/^[.\s`~-]+/, "").trim();
2077
+ cleaned = cleaned.replace(/[.\s`~-]+$/, "").trim();
2078
+ const lines = cleaned.split("\n").map((line) => line.trim()).filter((line) => line);
1997
2079
  const uniqueLines = [];
1998
2080
  const seen = /* @__PURE__ */ new Set();
1999
2081
  for (const line of lines) {
@@ -2010,13 +2092,14 @@ async function generateAICommitMessage(config2) {
2010
2092
  const language = aiConfig.language || "zh-CN";
2011
2093
  const detailedDescription = aiConfig.detailedDescription !== false;
2012
2094
  const maxTokens = aiConfig.maxTokens || (detailedDescription ? 400 : 200);
2095
+ const useEmoji = aiConfig.useEmoji !== void 0 ? aiConfig.useEmoji : config2.useEmoji !== false;
2013
2096
  const diff = getGitDiff();
2014
2097
  if (!diff) {
2015
2098
  throw new Error("\u6CA1\u6709\u68C0\u6D4B\u5230\u4EE3\u7801\u66F4\u6539");
2016
2099
  }
2017
2100
  const maxDiffLength = detailedDescription ? 6e3 : 4e3;
2018
2101
  const truncatedDiff = diff.length > maxDiffLength ? diff.slice(0, maxDiffLength) + "\n..." : diff;
2019
- const prompt = buildPrompt(truncatedDiff, language, detailedDescription);
2102
+ const prompt = buildPrompt(truncatedDiff, language, detailedDescription, useEmoji);
2020
2103
  const providerInfo = AI_PROVIDERS[provider];
2021
2104
  if (!providerInfo) {
2022
2105
  throw new Error(`\u4E0D\u652F\u6301\u7684 AI \u63D0\u4F9B\u5546: ${provider}`);
@@ -2248,11 +2331,13 @@ async function commit() {
2248
2331
  console.log("");
2249
2332
  return;
2250
2333
  }
2251
- const escapedMessage = message.replace(/"/g, '\\"');
2252
- execSync5(`git commit -m "${escapedMessage}"`, { stdio: "pipe" });
2334
+ execSync5(`git commit -F -`, {
2335
+ input: message
2336
+ });
2253
2337
  spinner.succeed("\u63D0\u4EA4\u6210\u529F");
2254
2338
  const commitHash = execOutput("git rev-parse --short HEAD");
2255
2339
  console.log(colors.dim(`commit: ${commitHash}`));
2340
+ console.log("");
2256
2341
  } catch (error) {
2257
2342
  spinner.fail("\u63D0\u4EA4\u5931\u8D25");
2258
2343
  console.log("");
@@ -2264,6 +2349,7 @@ async function commit() {
2264
2349
  console.log(colors.yellow("\u4F60\u53EF\u4EE5\u624B\u52A8\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4:"));
2265
2350
  console.log(colors.cyan(` git commit -m "${message}"`));
2266
2351
  console.log("");
2352
+ throw error;
2267
2353
  }
2268
2354
  }
2269
2355
  async function buildManualCommitMessage(config2) {
@@ -2345,83 +2431,6 @@ ${issues}`;
2345
2431
  return message;
2346
2432
  }
2347
2433
 
2348
- // src/commands/help.ts
2349
- init_utils();
2350
- function showHelp() {
2351
- return `
2352
- \u5206\u652F\u547D\u4EE4:
2353
- gw feature [--base <branch>] \u521B\u5EFA feature \u5206\u652F
2354
- gw feat [--base <branch>] \u540C\u4E0A (\u522B\u540D)
2355
- gw f [--base <branch>] \u540C\u4E0A (\u522B\u540D)
2356
-
2357
- gw hotfix [--base <branch>] \u521B\u5EFA hotfix \u5206\u652F
2358
- gw fix [--base <branch>] \u540C\u4E0A (\u522B\u540D)
2359
- gw h [--base <branch>] \u540C\u4E0A (\u522B\u540D)
2360
-
2361
- gw delete [branch] \u5220\u9664\u672C\u5730/\u8FDC\u7A0B\u5206\u652F
2362
- gw del [branch] \u540C\u4E0A (\u522B\u540D)
2363
- gw d [branch] \u540C\u4E0A (\u522B\u540D)
2364
-
2365
- Tag \u547D\u4EE4:
2366
- gw tags [prefix] \u5217\u51FA\u6240\u6709 tag\uFF0C\u53EF\u6309\u524D\u7F00\u8FC7\u6EE4
2367
- gw ts [prefix] \u540C\u4E0A (\u522B\u540D)
2368
-
2369
- gw tag [prefix] \u4EA4\u4E92\u5F0F\u9009\u62E9\u7248\u672C\u7C7B\u578B\u5E76\u521B\u5EFA tag
2370
- gw t [prefix] \u540C\u4E0A (\u522B\u540D)
2371
-
2372
- gw tag:delete \u5220\u9664 tag
2373
- gw td \u540C\u4E0A (\u522B\u540D)
2374
-
2375
- gw tag:update \u91CD\u547D\u540D tag
2376
- gw tu \u540C\u4E0A (\u522B\u540D)
2377
-
2378
- \u53D1\u5E03\u547D\u4EE4:
2379
- gw release \u4EA4\u4E92\u5F0F\u9009\u62E9\u7248\u672C\u53F7\u5E76\u66F4\u65B0 package.json
2380
- gw r \u540C\u4E0A (\u522B\u540D)
2381
-
2382
- \u914D\u7F6E\u547D\u4EE4:
2383
- gw init \u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6
2384
- \u2022 \u5168\u5C40\u914D\u7F6E: ~/.gwrc.json (\u6240\u6709\u9879\u76EE\u751F\u6548)
2385
- \u2022 \u9879\u76EE\u914D\u7F6E: .gwrc.json (\u4EC5\u5F53\u524D\u9879\u76EE)
2386
- \u8FD0\u884C\u65F6\u53EF\u9009\u62E9\u914D\u7F6E\u8303\u56F4
2387
-
2388
- \u66F4\u65B0\u547D\u4EE4:
2389
- gw update \u68C0\u67E5\u5E76\u66F4\u65B0\u5230\u6700\u65B0\u7248\u672C
2390
- gw upt \u540C\u4E0A (\u522B\u540D)
2391
-
2392
- \u6E05\u7406\u547D\u4EE4:
2393
- gw clean \u6E05\u7406\u7F13\u5B58\u6587\u4EF6
2394
-
2395
- Stash \u547D\u4EE4:
2396
- gw stash \u4EA4\u4E92\u5F0F\u7BA1\u7406 stash
2397
- gw s \u540C\u4E0A (\u522B\u540D)
2398
- gw st \u540C\u4E0A (\u522B\u540D)
2399
-
2400
- Commit \u547D\u4EE4:
2401
- gw commit \u4EA4\u4E92\u5F0F\u63D0\u4EA4 (Conventional Commits + Gitmoji)
2402
- gw c \u540C\u4E0A (\u522B\u540D)
2403
- gw cm \u540C\u4E0A (\u522B\u540D)
2404
-
2405
- \u793A\u4F8B:
2406
- gw f \u57FA\u4E8E main/master \u521B\u5EFA feature \u5206\u652F
2407
- gw f --base develop \u57FA\u4E8E develop \u5206\u652F\u521B\u5EFA feature \u5206\u652F
2408
- gw h --base release \u57FA\u4E8E release \u5206\u652F\u521B\u5EFA hotfix \u5206\u652F
2409
- gw d \u4EA4\u4E92\u5F0F\u9009\u62E9\u5E76\u5220\u9664\u5206\u652F
2410
- gw d feature/xxx \u76F4\u63A5\u5220\u9664\u6307\u5B9A\u5206\u652F
2411
- gw ts v \u5217\u51FA\u6240\u6709 v \u5F00\u5934\u7684 tag
2412
- gw t \u4EA4\u4E92\u5F0F\u521B\u5EFA tag
2413
- gw td \u4EA4\u4E92\u5F0F\u5220\u9664 tag
2414
- gw tu \u4EA4\u4E92\u5F0F\u4FEE\u6539 tag
2415
- gw r \u4EA4\u4E92\u5F0F\u53D1\u5E03\u7248\u672C
2416
- gw s \u4EA4\u4E92\u5F0F\u7BA1\u7406 stash
2417
- gw c \u4EA4\u4E92\u5F0F\u63D0\u4EA4\u4EE3\u7801
2418
-
2419
- \u5206\u652F\u547D\u540D\u683C\u5F0F:
2420
- feature/${TODAY}-<Story ID>-<\u63CF\u8FF0>
2421
- hotfix/${TODAY}-<Issue ID>-<\u63CF\u8FF0>
2422
- `;
2423
- }
2424
-
2425
2434
  // src/index.ts
2426
2435
  init_update_notifier();
2427
2436
 
@@ -2561,6 +2570,320 @@ async function update(currentVersion) {
2561
2570
  }
2562
2571
  }
2563
2572
 
2573
+ // src/commands/log.ts
2574
+ init_utils();
2575
+ import { execSync as execSync8 } from "child_process";
2576
+ import boxen3 from "boxen";
2577
+ import { spawn } from "child_process";
2578
+ function parseGitLog(output) {
2579
+ const commits = [];
2580
+ const lines = output.trim().split("\n");
2581
+ for (const line of lines) {
2582
+ if (!line.trim()) continue;
2583
+ const parts = line.split("|");
2584
+ if (parts.length >= 6) {
2585
+ commits.push({
2586
+ hash: parts[0],
2587
+ shortHash: parts[1],
2588
+ subject: parts[2],
2589
+ author: parts[3],
2590
+ date: parts[4],
2591
+ relativeDate: parts[5],
2592
+ refs: parts[6] || ""
2593
+ });
2594
+ }
2595
+ }
2596
+ return commits;
2597
+ }
2598
+ function getCommitTypeIcon(subject) {
2599
+ const lowerSubject = subject.toLowerCase();
2600
+ if (lowerSubject.includes("feat") || lowerSubject.includes("feature")) return "\u2728";
2601
+ if (lowerSubject.includes("fix") || lowerSubject.includes("bug")) return "\u{1F41B}";
2602
+ if (lowerSubject.includes("docs") || lowerSubject.includes("doc")) return "\u{1F4DA}";
2603
+ if (lowerSubject.includes("style")) return "\u{1F484}";
2604
+ if (lowerSubject.includes("refactor")) return "\u267B\uFE0F";
2605
+ if (lowerSubject.includes("test")) return "\u{1F9EA}";
2606
+ if (lowerSubject.includes("chore")) return "\u{1F527}";
2607
+ if (lowerSubject.includes("perf")) return "\u26A1";
2608
+ if (lowerSubject.includes("ci")) return "\u{1F477}";
2609
+ if (lowerSubject.includes("build")) return "\u{1F4E6}";
2610
+ if (lowerSubject.includes("revert")) return "\u23EA";
2611
+ if (lowerSubject.includes("merge")) return "\u{1F500}";
2612
+ if (lowerSubject.includes("release") || lowerSubject.includes("version")) return "\u{1F516}";
2613
+ return "\u{1F4DD}";
2614
+ }
2615
+ function groupCommitsByDate(commits) {
2616
+ const groups = /* @__PURE__ */ new Map();
2617
+ for (const commit2 of commits) {
2618
+ const date = commit2.date;
2619
+ if (!groups.has(date)) {
2620
+ groups.set(date, []);
2621
+ }
2622
+ groups.get(date).push(commit2);
2623
+ }
2624
+ return groups;
2625
+ }
2626
+ function formatRelativeTime(relativeDate) {
2627
+ let result = relativeDate;
2628
+ const timeMap = {
2629
+ "second": "\u79D2",
2630
+ "seconds": "\u79D2",
2631
+ "minute": "\u5206\u949F",
2632
+ "minutes": "\u5206\u949F",
2633
+ "hour": "\u5C0F\u65F6",
2634
+ "hours": "\u5C0F\u65F6",
2635
+ "day": "\u5929",
2636
+ "days": "\u5929",
2637
+ "week": "\u5468",
2638
+ "weeks": "\u5468",
2639
+ "month": "\u4E2A\u6708",
2640
+ "months": "\u4E2A\u6708",
2641
+ "year": "\u5E74",
2642
+ "years": "\u5E74",
2643
+ "ago": "\u524D"
2644
+ };
2645
+ for (const [en, zh] of Object.entries(timeMap)) {
2646
+ result = result.replace(new RegExp(`\\b${en}\\b`, "g"), zh);
2647
+ }
2648
+ result = result.replace(/(\d+)\s+(秒|分钟|小时|天|周|个月|年)\s+前/g, "$1$2\u524D");
2649
+ const match = result.match(/(\d+)(分钟|小时|天|周|个月|年)前/);
2650
+ if (match) {
2651
+ const num = parseInt(match[1]);
2652
+ const unit = match[2];
2653
+ if (unit === "\u5206\u949F" && num >= 60) {
2654
+ const hours = Math.floor(num / 60);
2655
+ return `${hours}\u5C0F\u65F6\u524D`;
2656
+ }
2657
+ if (unit === "\u5C0F\u65F6" && num >= 24) {
2658
+ const days = Math.floor(num / 24);
2659
+ return `${days}\u5929\u524D`;
2660
+ }
2661
+ if (unit === "\u5929" && num >= 7 && num < 30) {
2662
+ const weeks = Math.floor(num / 7);
2663
+ return `${weeks}\u5468\u524D`;
2664
+ }
2665
+ if (unit === "\u5929" && num >= 30) {
2666
+ const months = Math.floor(num / 30);
2667
+ return `${months}\u4E2A\u6708\u524D`;
2668
+ }
2669
+ if (unit === "\u5468" && num >= 4) {
2670
+ const months = Math.floor(num / 4);
2671
+ return `${months}\u4E2A\u6708\u524D`;
2672
+ }
2673
+ if (unit === "\u4E2A\u6708" && num >= 12) {
2674
+ const years = Math.floor(num / 12);
2675
+ return `${years}\u5E74\u524D`;
2676
+ }
2677
+ }
2678
+ return result;
2679
+ }
2680
+ function parseCommitSubject(subject) {
2681
+ if (subject.includes(" - ")) {
2682
+ const parts = subject.split(" - ");
2683
+ const title = parts[0].trim();
2684
+ const tasks = parts.slice(1).map((task) => task.trim()).filter((task) => task.length > 0);
2685
+ return { title, tasks };
2686
+ }
2687
+ return { title: subject, tasks: [] };
2688
+ }
2689
+ function supportsColor() {
2690
+ return true;
2691
+ }
2692
+ function formatTimelineStyle(commits) {
2693
+ const groupedCommits = groupCommitsByDate(commits);
2694
+ let output = "";
2695
+ const sortedDates = Array.from(groupedCommits.keys()).sort(
2696
+ (a, b) => new Date(b).getTime() - new Date(a).getTime()
2697
+ );
2698
+ const useColors = supportsColor() || process.env.FORCE_COLOR;
2699
+ for (let dateIndex = 0; dateIndex < sortedDates.length; dateIndex++) {
2700
+ const date = sortedDates[dateIndex];
2701
+ const dateCommits = groupedCommits.get(date);
2702
+ const dateTitle = `\u{1F4C5} Commits on ${date}`;
2703
+ if (useColors) {
2704
+ output += "\n" + colors.bold(colors.yellow(dateTitle)) + "\n\n";
2705
+ } else {
2706
+ output += "\n" + dateTitle + "\n\n";
2707
+ }
2708
+ for (let commitIndex = 0; commitIndex < dateCommits.length; commitIndex++) {
2709
+ const commit2 = dateCommits[commitIndex];
2710
+ const icon = getCommitTypeIcon(commit2.subject);
2711
+ const { title, tasks } = parseCommitSubject(commit2.subject);
2712
+ const commitContent = [];
2713
+ if (useColors) {
2714
+ commitContent.push(`${icon} ${colors.bold(colors.white(title))}`);
2715
+ } else {
2716
+ commitContent.push(`${icon} ${title}`);
2717
+ }
2718
+ if (tasks.length > 0) {
2719
+ commitContent.push("");
2720
+ tasks.forEach((task) => {
2721
+ if (useColors) {
2722
+ commitContent.push(` ${colors.dim("\u2013")} ${colors.dim(task)}`);
2723
+ } else {
2724
+ commitContent.push(` \u2013 ${task}`);
2725
+ }
2726
+ });
2727
+ }
2728
+ commitContent.push("");
2729
+ if (useColors) {
2730
+ commitContent.push(`${colors.dim("\u{1F464}")} ${colors.blue(commit2.author)} ${colors.dim("committed")} ${colors.green(formatRelativeTime(commit2.relativeDate))}`);
2731
+ commitContent.push(`${colors.dim("\u{1F517}")} ${colors.orange("#" + commit2.shortHash)}`);
2732
+ if (commit2.refs && commit2.refs.trim()) {
2733
+ const refs = commit2.refs.trim();
2734
+ const refParts = refs.split(", ");
2735
+ const branches = [];
2736
+ const tags = [];
2737
+ refParts.forEach((ref) => {
2738
+ if (ref.startsWith("tag: ")) {
2739
+ tags.push(ref.replace("tag: ", ""));
2740
+ } else if (ref.includes("/") || ref === "HEAD") {
2741
+ branches.push(ref);
2742
+ } else {
2743
+ branches.push(ref);
2744
+ }
2745
+ });
2746
+ if (branches.length > 0) {
2747
+ commitContent.push(`${colors.dim("\u{1F33F}")} ${colors.lightPurple(branches.join(", "))}`);
2748
+ }
2749
+ if (tags.length > 0) {
2750
+ const tagText = tags.map((tag) => `tag ${tag}`).join(", ");
2751
+ commitContent.push(`${colors.dim("\u{1F516}")} ${colors.yellow(tagText)}`);
2752
+ }
2753
+ }
2754
+ } else {
2755
+ commitContent.push(`\u{1F464} ${commit2.author} committed ${formatRelativeTime(commit2.relativeDate)}`);
2756
+ commitContent.push(`\u{1F517} #${commit2.shortHash}`);
2757
+ if (commit2.refs && commit2.refs.trim()) {
2758
+ const refs = commit2.refs.trim();
2759
+ const refParts = refs.split(", ");
2760
+ const branches = [];
2761
+ const tags = [];
2762
+ refParts.forEach((ref) => {
2763
+ if (ref.startsWith("tag: ")) {
2764
+ tags.push(ref.replace("tag: ", ""));
2765
+ } else if (ref.includes("/") || ref === "HEAD") {
2766
+ branches.push(ref);
2767
+ } else {
2768
+ branches.push(ref);
2769
+ }
2770
+ });
2771
+ if (branches.length > 0) {
2772
+ commitContent.push(`\u{1F33F} ${branches.join(", ")}`);
2773
+ }
2774
+ if (tags.length > 0) {
2775
+ const tagText = tags.map((tag) => `tag ${tag}`).join(", ");
2776
+ commitContent.push(`\u{1F516} ${tagText}`);
2777
+ }
2778
+ }
2779
+ }
2780
+ const commitBox = boxen3(commitContent.join("\n"), {
2781
+ padding: { top: 0, bottom: 0, left: 1, right: 1 },
2782
+ margin: { top: 0, bottom: 1, left: 0, right: 0 },
2783
+ borderStyle: "round",
2784
+ borderColor: "gray"
2785
+ });
2786
+ output += commitBox + "\n";
2787
+ }
2788
+ }
2789
+ return output;
2790
+ }
2791
+ function startInteractivePager(content) {
2792
+ const pager = process.env.PAGER || "less";
2793
+ try {
2794
+ const pagerProcess = spawn(pager, ["-R", "-S", "-F", "-X", "-i"], {
2795
+ stdio: ["pipe", "inherit", "inherit"],
2796
+ env: { ...process.env, LESS: "-R -S -F -X -i" }
2797
+ });
2798
+ pagerProcess.stdin.write(content);
2799
+ pagerProcess.stdin.end();
2800
+ pagerProcess.on("exit", () => {
2801
+ });
2802
+ pagerProcess.on("error", (err) => {
2803
+ console.log(content);
2804
+ });
2805
+ } catch (error) {
2806
+ console.log(content);
2807
+ }
2808
+ }
2809
+ function executeTimelineLog(options) {
2810
+ try {
2811
+ let cmd = 'git log --pretty=format:"%H|%h|%s|%an|%ad|%ar|%D" --date=short';
2812
+ if (options.limit && !options.interactive) cmd += ` -${options.limit}`;
2813
+ if (options.author) cmd += ` --author="${options.author}"`;
2814
+ if (options.since) cmd += ` --since="${options.since}"`;
2815
+ if (options.until) cmd += ` --until="${options.until}"`;
2816
+ if (options.grep) cmd += ` --grep="${options.grep}"`;
2817
+ if (options.all) cmd += ` --all`;
2818
+ if (options.interactive && !options.limit) {
2819
+ cmd += ` -50`;
2820
+ }
2821
+ const output = execSync8(cmd, {
2822
+ encoding: "utf8",
2823
+ stdio: "pipe",
2824
+ maxBuffer: 1024 * 1024 * 10
2825
+ });
2826
+ if (output.trim()) {
2827
+ const commits = parseGitLog(output);
2828
+ let fullOutput = "";
2829
+ const title = `\u{1F4CA} \u5171\u663E\u793A ${commits.length} \u4E2A\u63D0\u4EA4`;
2830
+ fullOutput += "\n" + boxen3(title, {
2831
+ padding: { top: 0, bottom: 0, left: 2, right: 2 },
2832
+ margin: { top: 0, bottom: 1, left: 0, right: 0 },
2833
+ borderStyle: "double",
2834
+ borderColor: "green",
2835
+ textAlignment: "center"
2836
+ }) + "\n";
2837
+ const timelineOutput = formatTimelineStyle(commits);
2838
+ fullOutput += timelineOutput;
2839
+ if (options.interactive) {
2840
+ startInteractivePager(fullOutput);
2841
+ } else {
2842
+ console.log(fullOutput);
2843
+ }
2844
+ } else {
2845
+ const noCommitsMsg = "\n" + boxen3("\u{1F4ED} \u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u63D0\u4EA4\u8BB0\u5F55", {
2846
+ padding: { top: 0, bottom: 0, left: 2, right: 2 },
2847
+ borderStyle: "round",
2848
+ borderColor: "yellow",
2849
+ textAlignment: "center"
2850
+ });
2851
+ if (options.interactive) {
2852
+ startInteractivePager(noCommitsMsg);
2853
+ } else {
2854
+ console.log(noCommitsMsg);
2855
+ }
2856
+ }
2857
+ } catch (error) {
2858
+ let errorMessage = "\u274C \u6267\u884C\u5931\u8D25";
2859
+ if (error.status === 128) {
2860
+ errorMessage = "\u274C Git\u4ED3\u5E93\u9519\u8BEF\u6216\u6CA1\u6709\u63D0\u4EA4\u8BB0\u5F55";
2861
+ } else {
2862
+ errorMessage = `\u274C \u6267\u884C\u5931\u8D25: ${error.message}`;
2863
+ }
2864
+ const errorBox = "\n" + boxen3(errorMessage, {
2865
+ padding: { top: 0, bottom: 0, left: 2, right: 2 },
2866
+ borderStyle: "round",
2867
+ borderColor: "red",
2868
+ textAlignment: "center"
2869
+ });
2870
+ if (options.interactive) {
2871
+ startInteractivePager(errorBox);
2872
+ } else {
2873
+ console.log(errorBox);
2874
+ }
2875
+ }
2876
+ }
2877
+ async function log(options = {}) {
2878
+ if (options.interactive === void 0) {
2879
+ options.interactive = true;
2880
+ }
2881
+ if (!options.interactive && !options.limit) {
2882
+ options.limit = 10;
2883
+ }
2884
+ executeTimelineLog(options);
2885
+ }
2886
+
2564
2887
  // src/index.ts
2565
2888
  process.on("uncaughtException", (err) => {
2566
2889
  if (err instanceof ExitPromptError) {
@@ -2586,7 +2909,7 @@ process.on("SIGTERM", () => {
2586
2909
  console.log("");
2587
2910
  process.exit(0);
2588
2911
  });
2589
- var version = true ? "0.3.0" : "0.0.0-dev";
2912
+ var version = true ? "0.3.3" : "0.0.0-dev";
2590
2913
  async function mainMenu() {
2591
2914
  console.log(
2592
2915
  colors.green(`
@@ -2644,7 +2967,11 @@ async function mainMenu() {
2644
2967
  value: "stash"
2645
2968
  },
2646
2969
  {
2647
- name: `[b] \u2699\uFE0F \u521D\u59CB\u5316\u914D\u7F6E ${colors.dim("gw init")}`,
2970
+ name: `[b] \u{1F4CA} \u67E5\u770B\u65E5\u5FD7 ${colors.dim("gw log")}`,
2971
+ value: "log"
2972
+ },
2973
+ {
2974
+ name: `[c] \u2699\uFE0F \u521D\u59CB\u5316\u914D\u7F6E ${colors.dim("gw init")}`,
2648
2975
  value: "init"
2649
2976
  },
2650
2977
  { name: "[0] \u2753 \u5E2E\u52A9", value: "help" },
@@ -2693,11 +3020,15 @@ async function mainMenu() {
2693
3020
  checkGitRepo();
2694
3021
  await stash();
2695
3022
  break;
3023
+ case "log":
3024
+ checkGitRepo();
3025
+ await log();
3026
+ break;
2696
3027
  case "init":
2697
3028
  await init();
2698
3029
  break;
2699
3030
  case "help":
2700
- console.log(showHelp());
3031
+ cli.outputHelp();
2701
3032
  break;
2702
3033
  case "exit":
2703
3034
  break;
@@ -2764,6 +3095,13 @@ cli.command("commit", "\u4EA4\u4E92\u5F0F\u63D0\u4EA4 (Conventional Commits + Gi
2764
3095
  cli.command("update", "\u68C0\u67E5\u5E76\u66F4\u65B0\u5230\u6700\u65B0\u7248\u672C").alias("upt").action(async () => {
2765
3096
  return update(version);
2766
3097
  });
3098
+ cli.command("log", "\u4EA4\u4E92\u5F0FGit\u65E5\u5FD7\u67E5\u770B (\u5206\u9875\u6A21\u5F0F)").alias("ls").alias("l").option("--limit <number>", "\u9650\u5236\u663E\u793A\u6570\u91CF").action(async (options) => {
3099
+ await checkForUpdates(version, "@zjex/git-workflow");
3100
+ checkGitRepo();
3101
+ const logOptions = { interactive: true };
3102
+ if (options.limit) logOptions.limit = parseInt(options.limit);
3103
+ return log(logOptions);
3104
+ });
2767
3105
  cli.command("clean", "\u6E05\u7406\u7F13\u5B58\u6587\u4EF6").action(async () => {
2768
3106
  const { clearUpdateCache: clearUpdateCache3 } = await Promise.resolve().then(() => (init_update_notifier(), update_notifier_exports));
2769
3107
  clearUpdateCache3();
@@ -2771,15 +3109,15 @@ cli.command("clean", "\u6E05\u7406\u7F13\u5B58\u6587\u4EF6").action(async () =>
2771
3109
  console.log(colors.green("\u2714 \u7F13\u5B58\u5DF2\u6E05\u7406"));
2772
3110
  console.log("");
2773
3111
  });
2774
- cli.help((sections) => {
2775
- sections.push({
2776
- body: showHelp()
2777
- });
2778
- });
2779
3112
  cli.option("-v, --version", "\u663E\u793A\u7248\u672C\u53F7");
2780
- var args = process.argv.slice(2);
2781
- if (args.includes("-v") || args.includes("--version")) {
3113
+ cli.option("-h, --help", "\u663E\u793A\u5E2E\u52A9\u4FE1\u606F");
3114
+ var processArgs = process.argv.slice(2);
3115
+ if (processArgs.includes("-v") || processArgs.includes("--version")) {
2782
3116
  console.log(colors.yellow(`v${version}`));
2783
3117
  process.exit(0);
2784
3118
  }
3119
+ if (processArgs.includes("-h") || processArgs.includes("--help")) {
3120
+ cli.outputHelp();
3121
+ process.exit(0);
3122
+ }
2785
3123
  cli.parse();