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 +17 -7
- package/index.js +2 -0
- package/package.json +10 -6
- package/src/config.js +3 -0
- package/src/gitCommit.js +223 -59
- package/src/utils/index.js +10 -1
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
|
-
|
|
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
package/package.json
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zen-gitsync",
|
|
3
|
-
"version": "1.3.
|
|
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
|
|
19
|
-
"
|
|
20
|
-
"
|
|
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
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
112
|
+
judgeHelp() {
|
|
113
|
+
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
|
114
|
+
showHelp();
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
73
118
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
85
|
-
|
|
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
|
-
|
|
92
|
-
|
|
147
|
+
if (!autoCommit && !commitMessageArg) {
|
|
148
|
+
// 如果没有 -y 参数,则等待用户输入提交信息
|
|
149
|
+
this.commitMessage = await question('请输入提交信息:');
|
|
150
|
+
}
|
|
93
151
|
|
|
94
|
-
|
|
95
|
-
// 如果没有 -y 参数,则等待用户输入提交信息
|
|
96
|
-
this.commitMessage = await question('请输入提交信息:');
|
|
97
|
-
}
|
|
152
|
+
this.statusOutput.includes('(use "git add') && this.execSyncGitCommand('git add .')
|
|
98
153
|
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
options.spinner
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
}
|
package/src/utils/index.js
CHANGED
|
@@ -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
|
-
|
|
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};
|