zen-gitsync 1.3.1 → 1.3.6

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
@@ -15,10 +15,8 @@ npm install -g zen-gitsync
15
15
 
16
16
  1. 在终端中,输入 `g` 并按回车。
17
17
  2. 输入提交信息,按回车确认提交。
18
- 3. 工具将自动执行以下操作:
19
- - `git add .`
20
- - `git commit -m "你的提交信息"`
21
- - `git push`
18
+ 3. 工具将自动查看远程分支并自动提交
19
+
22
20
 
23
21
  ### 示例:
24
22
  #### 交互式提交:
@@ -30,18 +28,30 @@ $ g
30
28
  ```bash
31
29
  $ g -y
32
30
  ```
31
+ #### 传入message直接提交:
32
+ ```bash
33
+ $ g -m <message>
34
+ $ g -m=<message>
35
+ ```
36
+
37
+ #### 查看帮助
38
+ ```shell
39
+ $ g -h
40
+ $ g --help
41
+ ```
42
+
33
43
  #### 定时执行自动提交,默认间隔1小时
34
44
  ```bash
35
45
  $ g -y --interval
36
- $ g -y --interval=秒数
46
+ $ g -y --interval=<seconds>
37
47
  ```
38
48
  #### 指定目录提交
39
49
  ```bash
40
- $ g --path=./
50
+ $ g --path=<path>
41
51
  ```
42
52
 
43
53
  ```bash
44
- $ g --cwd=./
54
+ $ g --cwd=<path>
45
55
  ```
46
56
 
47
57
  #### 添加项目script
package/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import config from './src/config.js'
2
+ export default config
package/package.json CHANGED
@@ -1,23 +1,27 @@
1
1
  {
2
2
  "name": "zen-gitsync",
3
- "version": "1.3.1",
3
+ "version": "1.3.6",
4
4
  "description": "一个 git 自动查看差异并提交的工具",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "g": "node ./src/gitCommit.js",
9
+ "g:m": "node ./src/gitCommit.js -m='test'",
10
+ "g:m2": "node ./src/gitCommit.js -m testmsg",
9
11
  "g:y": "node ./src/gitCommit.js -y",
10
12
  "g:y:interval": "node ./src/gitCommit.js -y --interval",
11
13
  "g:y:interval10": "node ./src/gitCommit.js -y --interval=10",
12
14
  "g:cwd": "node ./src/gitCommit.js --path=./",
15
+ "g:cwd2": "node ./src/gitCommit.js --path=../",
13
16
  "g:no-diff": "node ./src/gitCommit.js --no-diff",
14
17
  "g:log": "node ./src/gitCommit.js log",
15
- "g:log5": "node ./src/gitCommit.js log --n=5"
18
+ "g:log5": "node ./src/gitCommit.js log --n=5",
19
+ "g:h": "node ./src/gitCommit.js -h"
16
20
  },
17
21
  "files": [
18
- "src/gitCommit.js",
19
- "src/utils/index.js",
20
- "package.json"
22
+ "src/*",
23
+ "package.json",
24
+ "index.js"
21
25
  ],
22
26
  "bin": {
23
27
  "g": "./src/gitCommit.js"
@@ -26,7 +30,7 @@
26
30
  "type": "git",
27
31
  "url": "git+https://github.com/xz333221/zen-gitsync.git"
28
32
  },
29
- "keywords": [],
33
+ "keywords": ["gitsync", "git"],
30
34
  "author": "",
31
35
  "license": "MIT",
32
36
  "bugs": {
package/src/config.js ADDED
@@ -0,0 +1,3 @@
1
+ export default {
2
+ "defaultCommitMessage": "submit"
3
+ }
package/src/gitCommit.js CHANGED
@@ -2,13 +2,53 @@
2
2
 
3
3
  import {exec, execSync} from 'child_process'
4
4
  import os from 'os'
5
- import {coloredLog} from './utils/index.js';
5
+ import {coloredLog, errorLog} from './utils/index.js';
6
6
  import readline from 'readline'
7
7
  import ora from 'ora';
8
8
  import chalk from 'chalk';
9
9
  import boxen from 'boxen';
10
+ import config from './config.js'
11
+
12
+ const {defaultCommitMessage} = config
10
13
 
11
14
  let timer = null
15
+ const showHelp = () => {
16
+ const helpMessage = `
17
+ Usage: g [options]
18
+
19
+ Options:
20
+ -h, --help Show this help message
21
+ -y Auto commit with default message
22
+ -m <message> Commit message (use quotes if message contains spaces)
23
+ -m=<message> Commit message (use this form without spaces around '=')
24
+ --path=<path> Set custom working directory
25
+ --cwd=<path> Set custom working directory
26
+ --interval=<seconds> Set interval time for automatic commits (in seconds)
27
+ log Show git commit logs
28
+ --n=<number> Number of commits to show with --log
29
+ --no-diff Skip displaying git diff
30
+
31
+ Example:
32
+ g -m "Initial commit" Commit with a custom message
33
+ g -m=Fix-bug Commit with a custom message (no spaces around '=')
34
+ g -y Auto commit with the default message
35
+ g -y --interval=600 Commit every 10 minutes (600 seconds)
36
+ g --path=/path/to/repo Specify a custom working directory
37
+ g log Show recent commit logs
38
+ g log --n=5 Show the last 5 commits with --log
39
+
40
+ Add auto submit in package.json:
41
+ "scripts": {
42
+ "g:y": "g -y"
43
+ }
44
+
45
+ Start a background process for automatic commits:
46
+ start /min cmd /k "g -y --path=your-folder --interval"
47
+ `;
48
+
49
+ console.log(helpMessage);
50
+ process.exit();
51
+ };
12
52
 
13
53
  const judgePlatform = () => {
14
54
  // 判断是否是 Windows 系统
@@ -51,7 +91,7 @@ class GitCommit {
51
91
  constructor(options) {
52
92
  this.statusOutput = null
53
93
  this.exit = options.exit
54
- this.commitMessage = `提交`
94
+ this.commitMessage = defaultCommitMessage
55
95
  this.init()
56
96
  }
57
97
 
@@ -61,59 +101,175 @@ class GitCommit {
61
101
  }
62
102
  }
63
103
 
64
- async init() {
65
- try {
66
- judgePlatform()
104
+ judgeLog() {
105
+ const logArg = process.argv.find(arg => arg === 'log');
106
+ if (logArg) {
107
+ this.printGitLog(); // 如果有 log 参数,打印 Git 提交记录
108
+ return true;
109
+ }
110
+ }
67
111
 
68
- const logArg = process.argv.find(arg => arg === 'log');
69
- if (logArg) {
70
- await this.printGitLog(); // 如果有 log 参数,打印 Git 提交记录
71
- return;
72
- }
112
+ judgeHelp() {
113
+ if (process.argv.includes('-h') || process.argv.includes('--help')) {
114
+ showHelp();
115
+ return true;
116
+ }
117
+ }
73
118
 
74
- this.statusOutput = this.execSyncGitCommand('git status')
75
- if (this.statusOutput.includes('nothing to commit, working tree clean')) {
76
- if (this.statusOutput.includes('use "git push')) {
77
- this.exec_push()
78
- } else {
79
- this.exec_exit();
119
+ execDiff() {
120
+ const no_diff = process.argv.find(arg => arg.startsWith('--no-diff'))
121
+ if (!no_diff) {
122
+ this.execSyncGitCommand('git diff --color=always', {
123
+ head: `git diff`
124
+ })
125
+ }
126
+ }
127
+
128
+ async execAddAndCommit() {
129
+ // 检查 -m 参数(提交信息)
130
+ const commitMessageArg = process.argv.find(arg => arg.startsWith('-m'));
131
+ if (commitMessageArg) {
132
+ if (commitMessageArg.includes('=')) {
133
+ // 处理 -m=<message> 的情况
134
+ this.commitMessage = commitMessageArg.split('=')[1]?.replace(/^['"]|['"]$/g, '') || defaultCommitMessage;
135
+ } else {
136
+ // 处理 -m <message> 的情况
137
+ const index = process.argv.indexOf(commitMessageArg);
138
+ if (index !== -1 && process.argv[index + 1]) {
139
+ this.commitMessage = process.argv[index + 1]?.replace(/^['"]|['"]$/g, '') || defaultCommitMessage;
80
140
  }
81
- return
82
141
  }
142
+ }
83
143
 
84
- const no_diff = process.argv.find(arg => arg.startsWith('--no-diff'))
85
- if(!no_diff){
86
- this.execSyncGitCommand('git diff --color=always', {
87
- head: `git diff`
88
- })
89
- }
144
+ // 检查命令行参数,判断是否有 -y 参数
145
+ const autoCommit = process.argv.includes('-y');
90
146
 
91
- // 检查命令行参数,判断是否有 -y 参数
92
- const autoCommit = process.argv.includes('-y');
147
+ if (!autoCommit && !commitMessageArg) {
148
+ // 如果没有 -y 参数,则等待用户输入提交信息
149
+ this.commitMessage = await question('请输入提交信息:');
150
+ }
93
151
 
94
- if (!autoCommit) {
95
- // 如果没有 -y 参数,则等待用户输入提交信息
96
- this.commitMessage = await question('请输入提交信息:');
97
- }
152
+ this.statusOutput.includes('(use "git add') && this.execSyncGitCommand('git add .')
98
153
 
99
- // 执行 git add .
100
- this.statusOutput.includes('(use "git add') && this.execSyncGitCommand('git add .')
154
+ // 执行 git commit
155
+ if (this.statusOutput.includes('Untracked files:') || this.statusOutput.includes('Changes not staged for commit') || this.statusOutput.includes('Changes to be committed')) {
156
+ this.execSyncGitCommand(`git commit -m "${this.commitMessage || defaultCommitMessage}"`)
157
+ }
158
+ }
101
159
 
102
- // 执行 git commit
103
- if (this.statusOutput.includes('Untracked files:') || this.statusOutput.includes('Changes not staged for commit') || this.statusOutput.includes('Changes to be committed')) {
104
- this.execSyncGitCommand(`git commit -m "${this.commitMessage || '提交'}"`)
160
+ async judgeRemote() {
161
+ try {
162
+ const spinner = ora('正在检查远程更新...').start();
163
+ // 检查是否有远程更新
164
+ // 先获取远程最新状态
165
+ await this.execGitCommand('git remote update', {
166
+ head: 'Fetching remote updates',
167
+ log: false
168
+ });
169
+ // 检查是否需要 pull
170
+ const res = await this.execGitCommand('git rev-list HEAD..@{u} --count', {
171
+ head: 'Checking if behind remote',
172
+ log: false
173
+ });
174
+ const behindCount = res.stdout.trim()
175
+ // 如果本地落后于远程
176
+ if (parseInt(behindCount) > 0) {
177
+ try {
178
+ spinner.stop();
179
+ // const spinner_pull = ora('发现远程更新,正在拉取...').start();
180
+ await this.execPull()
181
+
182
+ // // 尝试使用 --ff-only 拉取更新
183
+ // const res = await this.execGitCommand('git pull --ff-only', {
184
+ // spinner: spinner_pull,
185
+ // head: 'Pulling updates'
186
+ // });
187
+ console.log(chalk.green('✓ 已成功同步远程更新'));
188
+ } catch (pullError) {
189
+ // // 如果 --ff-only 拉取失败,尝试普通的 git pull
190
+ // console.log(chalk.yellow('⚠️ 无法快进合并,尝试普通合并...'));
191
+ // await this.execPull()
192
+ throw new Error(pullError)
193
+ }
194
+ } else {
195
+ spinner.stop();
196
+ console.log(chalk.green('✓ 本地已是最新'));
105
197
  }
198
+ } catch (e) {
199
+ // console.log(`e ==> `, e)
200
+ spinner.stop();
201
+ throw new Error(e)
202
+ }
203
+ }
106
204
 
205
+ async execPull() {
206
+ try {
107
207
  // 检查是否需要拉取更新
108
- this.statusOutput.includes('use "git pull') && this.execSyncGitCommand('git pull')
208
+ const spinner = ora('正在拉取代码...').start();
209
+ await this.execGitCommand('git pull', {
210
+ spinner
211
+ })
212
+ } catch (e) {
213
+ console.log(chalk.yellow('⚠️ 拉取远程更新合并失败,可能存在冲突,请手动处理'));
214
+ throw Error(e)
215
+ }
216
+ }
217
+
218
+ async init() {
219
+ try {
220
+ judgePlatform()
221
+
222
+ // 检查是否有 log 参数
223
+ if (this.judgeLog()) return
224
+
225
+ // 检查帮助参数
226
+ if (this.judgeHelp()) return
227
+
228
+ this.statusOutput = this.execSyncGitCommand('git status')
229
+ const hasUnmerged = this.statusOutput.includes('You have unmerged paths');
230
+ if (hasUnmerged) {
231
+ errorLog('错误', '存在未合并的文件,请先解决冲突')
232
+ process.exit(1);
233
+ }
234
+ // 先检查本地是否有未提交的更改
235
+ const hasLocalChanges = !this.statusOutput.includes('nothing to commit, working tree clean');
236
+ if (hasLocalChanges) {
237
+ // 检查是否有 --no-diff 参数
238
+ this.execDiff()
239
+
240
+ await this.execAddAndCommit()
109
241
 
110
- this.exec_push()
242
+ this.statusOutput.includes('use "git pull') && await this.execPull()
111
243
 
244
+ // 检查是否有远程更新
245
+ await this.judgeRemote() // 等待 judgeRemote 完成
112
246
 
247
+ this.exec_push()
248
+ } else {
249
+ if (this.statusOutput.includes('use "git push')) {
250
+ this.exec_push()
251
+ } else if (this.statusOutput.includes('use "git pull')) {
252
+ await this.execPull()
253
+ } else {
254
+ await this.judgeRemote() // 等待 judgeRemote 完成
255
+ this.exec_exit();
256
+ }
257
+ }
113
258
  } catch (e) {
114
- console.log(`e ==> `, e)
259
+ // console.log(`e ==> `, e)
260
+ // console.log(`e.message ==> `, e.message)
261
+ // 应该提供更具体的错误信息
262
+ // console.error('Git operation failed:', e.message);
263
+ // 考虑不同错误类型的处理
264
+ if (e.message.includes('not a git repository')) {
265
+ errorLog('错误', '当前目录不是git仓库')
266
+ } else if (e.message.includes('Permission denied')) {
267
+ errorLog('错误', '权限不足,请检查git配置')
268
+ }
269
+ process.exit(1);
115
270
  }
116
271
  }
272
+
117
273
  async printGitLog() {
118
274
  let n = 20;
119
275
  let logArg = process.argv.find(arg => arg.startsWith('--n='));
@@ -148,7 +304,7 @@ class GitCommit {
148
304
 
149
305
  // 使用 boxen 绘制带边框的消息
150
306
  let msg = ` SUCCESS: 提交完成
151
- message: ${this.commitMessage || '提交'}
307
+ message: ${this.commitMessage || defaultCommitMessage}
152
308
  time: ${new Date().toLocaleString()} `
153
309
  const message = chalk.green.bold(msg);
154
310
  const box = boxen(message, {
@@ -164,40 +320,48 @@ class GitCommit {
164
320
  }
165
321
 
166
322
  execSyncGitCommand(command, options = {}) {
323
+ let {encoding = 'utf-8', maxBuffer = 30 * 1024 * 1024, head = command, log = true} = options
167
324
  try {
168
- let {encoding = 'utf-8', maxBuffer = 30 * 1024 * 1024, head = command} = options
169
325
  let cwd = getCwd()
170
326
  const output = execSync(command, {encoding, maxBuffer, cwd})
171
- if(options.spinner){
327
+ if (options.spinner) {
172
328
  options.spinner.stop();
173
329
  }
174
330
  let result = output.trim()
175
- coloredLog(head, result)
331
+ log && coloredLog(head, result)
176
332
  return result
177
333
  } catch (e) {
178
- console.log(`执行命令出错 ==> `, command, e)
334
+ // console.log(`执行命令出错 ==> `, command, e)
335
+ log && coloredLog(command, e, 'error')
179
336
  throw new Error(e)
180
337
  }
181
338
  }
182
339
 
183
340
  execGitCommand(command, options = {}, callback) {
184
- let {encoding = 'utf-8', maxBuffer = 30 * 1024 * 1024} = options
185
- let cwd = getCwd()
186
- exec(command, {encoding, maxBuffer, cwd}, (error, stdout, stderr) => {
187
- if(options.spinner){
188
- options.spinner.stop();
189
- }
190
- if (error) {
191
- coloredLog(command, error, 'error')
192
- return
193
- }
194
- if (stdout) {
195
- coloredLog(command, stdout)
196
- }
197
- if (stderr) {
198
- coloredLog(command, stderr)
199
- }
200
- callback && callback(error, stdout, stderr)
341
+ return new Promise((resolve, reject) => {
342
+ let {encoding = 'utf-8', maxBuffer = 30 * 1024 * 1024, head = command, log = true} = options
343
+ let cwd = getCwd()
344
+ exec(command, {encoding, maxBuffer, cwd}, (error, stdout, stderr) => {
345
+ if (options.spinner) {
346
+ options.spinner.stop();
347
+ }
348
+ if (error) {
349
+ log && coloredLog(head, error, 'error')
350
+ reject(error)
351
+ return
352
+ }
353
+ if (stdout) {
354
+ log && coloredLog(head, stdout)
355
+ }
356
+ if (stderr) {
357
+ log && coloredLog(head, stderr)
358
+ }
359
+ resolve({
360
+ stdout,
361
+ stderr
362
+ })
363
+ callback && callback(error, stdout, stderr)
364
+ })
201
365
  })
202
366
  }
203
367
  }
@@ -17,6 +17,7 @@
17
17
  import stringWidth from 'string-width';
18
18
  import Table from 'cli-table3';
19
19
  import chalk from 'chalk';
20
+ import boxen from "boxen";
20
21
 
21
22
  const printTableWithHeaderUnderline = (head, content, style) => {
22
23
  // 获取终端的列数(宽度)
@@ -160,4 +161,12 @@ const coloredLog = (...args) => {
160
161
  const type = args[2] || 'common';
161
162
  tableLog(commandLine, content, type);
162
163
  }
163
- export {coloredLog};
164
+ const errorLog = (commandLine, content) => {
165
+ // 使用 boxen 绘制带边框的消息
166
+ let msg = ` FAIL ${commandLine}
167
+ content: ${content} `
168
+ const message = chalk.red.bold(msg);
169
+ const box = boxen(message);
170
+ console.log(box); // 打印带有边框的消息
171
+ }
172
+ export {coloredLog, errorLog};