create-branch-cli 1.0.0
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 +105 -0
- package/index.js +234 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# create-branch-cli
|
|
2
|
+
|
|
3
|
+
一个快速创建 Git 分支的命令行工具,支持自动生成规范的分支名称。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- 🚀 快速创建 Git 分支
|
|
8
|
+
- 📝 自动生成规范的分支名称
|
|
9
|
+
- 👤 首次使用自动保存用户信息(工号、姓名)
|
|
10
|
+
- 🐛 支持 feature 和 hotFix 两种分支类型
|
|
11
|
+
- 📅 自动添加日期后缀
|
|
12
|
+
|
|
13
|
+
## 分支命名规则
|
|
14
|
+
|
|
15
|
+
- **Feature 分支**: `feature/工号_姓名_需求标题_年月日`
|
|
16
|
+
- **HotFix 分支**: `hotFix/工号_姓名_需求标题_年月日`
|
|
17
|
+
|
|
18
|
+
示例:
|
|
19
|
+
- `feature/001_张三_用户登录功能_20251226`
|
|
20
|
+
- `hotFix/001_张三_修复登录bug_20251226`
|
|
21
|
+
|
|
22
|
+
## 安装
|
|
23
|
+
|
|
24
|
+
### 本地开发安装
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install -g
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
或者使用 npm link(在项目目录下):
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm link
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 发布到 npm(发布后其他人可全局安装)
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm publish
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
发布后,其他人可以通过以下命令安装:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install -g create-branch-cli
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 使用方法
|
|
49
|
+
|
|
50
|
+
### 首次使用
|
|
51
|
+
|
|
52
|
+
首次使用时,工具会提示您输入工号和姓名,这些信息会保存在 `~/.create-branch/config.json` 文件中。
|
|
53
|
+
|
|
54
|
+
### 创建 Feature 分支
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
create-branch 用户登录功能
|
|
58
|
+
# 或使用别名
|
|
59
|
+
cb 用户登录功能
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 创建 HotFix 分支
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
create-branch 修复登录bug -b
|
|
66
|
+
# 或
|
|
67
|
+
create-branch 修复登录bug --bug
|
|
68
|
+
# 或使用别名
|
|
69
|
+
cb 修复登录bug -b
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 查看帮助
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
create-branch
|
|
76
|
+
# 或
|
|
77
|
+
cb
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## 配置
|
|
81
|
+
|
|
82
|
+
用户信息保存在 `~/.create-branch/config.json` 文件中,格式如下:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"workId": "001",
|
|
87
|
+
"name": "张三"
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
如果需要修改用户信息,可以:
|
|
92
|
+
1. 直接编辑配置文件
|
|
93
|
+
2. 删除配置文件,下次使用时重新录入
|
|
94
|
+
|
|
95
|
+
## 注意事项
|
|
96
|
+
|
|
97
|
+
1. 使用前请确保当前目录是一个 Git 仓库
|
|
98
|
+
2. 如果分支已存在,工具会提示是否切换到已存在的分支
|
|
99
|
+
3. 需求标题中的空格会自动替换为下划线
|
|
100
|
+
4. 日期格式为 YYYYMMDD(例如:20251226)
|
|
101
|
+
|
|
102
|
+
## 许可证
|
|
103
|
+
|
|
104
|
+
ISC
|
|
105
|
+
|
package/index.js
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const readline = require('readline');
|
|
7
|
+
|
|
8
|
+
// 配置文件路径(存储在用户主目录)
|
|
9
|
+
const CONFIG_DIR = path.join(require('os').homedir(), '.create-branch');
|
|
10
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
11
|
+
|
|
12
|
+
// 工具函数
|
|
13
|
+
function log(message) {
|
|
14
|
+
console.log(`[${new Date().toLocaleTimeString()}] ${message}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function error(message) {
|
|
18
|
+
console.error(`[错误] ${message}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function success(message) {
|
|
22
|
+
console.log(`✅ ${message}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 读取配置文件
|
|
26
|
+
function readConfig() {
|
|
27
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
32
|
+
return JSON.parse(content);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
error(`读取配置文件失败: ${err.message}`);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 保存配置文件
|
|
40
|
+
function saveConfig(config) {
|
|
41
|
+
try {
|
|
42
|
+
// 确保配置目录存在
|
|
43
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
44
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');
|
|
47
|
+
return true;
|
|
48
|
+
} catch (err) {
|
|
49
|
+
error(`保存配置文件失败: ${err.message}`);
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 交互式输入
|
|
55
|
+
function question(query) {
|
|
56
|
+
const rl = readline.createInterface({
|
|
57
|
+
input: process.stdin,
|
|
58
|
+
output: process.stdout
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return new Promise(resolve => {
|
|
62
|
+
rl.question(query, answer => {
|
|
63
|
+
rl.close();
|
|
64
|
+
resolve(answer);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 首次使用,录入用户信息
|
|
70
|
+
async function initUserInfo() {
|
|
71
|
+
console.log('\n=== 首次使用,需要录入您的信息 ===\n');
|
|
72
|
+
|
|
73
|
+
const workId = await question('请输入工号: ');
|
|
74
|
+
if (!workId || !workId.trim()) {
|
|
75
|
+
error('工号不能为空');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const name = await question('请输入姓名: ');
|
|
80
|
+
if (!name || !name.trim()) {
|
|
81
|
+
error('姓名不能为空');
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const config = {
|
|
86
|
+
workId: workId.trim(),
|
|
87
|
+
name: name.trim()
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (saveConfig(config)) {
|
|
91
|
+
success('用户信息已保存!');
|
|
92
|
+
return config;
|
|
93
|
+
} else {
|
|
94
|
+
error('保存用户信息失败');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 获取当前日期(格式:YYYYMMDD)
|
|
100
|
+
function getCurrentDate() {
|
|
101
|
+
const now = new Date();
|
|
102
|
+
const year = now.getFullYear();
|
|
103
|
+
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
104
|
+
const day = String(now.getDate()).padStart(2, '0');
|
|
105
|
+
return `${year}${month}${day}`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 生成分支名
|
|
109
|
+
function generateBranchName(workId, name, title, isBug) {
|
|
110
|
+
const prefix = isBug ? 'hotFix' : 'feature';
|
|
111
|
+
const date = getCurrentDate();
|
|
112
|
+
// 将需求标题中的空格替换为下划线,并移除特殊字符
|
|
113
|
+
const cleanTitle = title.trim().replace(/\s+/g, '_').replace(/[^\w\u4e00-\u9fa5_-]/g, '');
|
|
114
|
+
return `${prefix}/${workId}_${name}_${cleanTitle}_${date}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 检查是否在 Git 仓库中
|
|
118
|
+
function isGitRepo() {
|
|
119
|
+
try {
|
|
120
|
+
execSync('git rev-parse --git-dir', { stdio: 'ignore' });
|
|
121
|
+
return true;
|
|
122
|
+
} catch (err) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 检查分支是否已存在
|
|
128
|
+
function branchExists(branchName) {
|
|
129
|
+
try {
|
|
130
|
+
const branches = execSync('git branch -a', { encoding: 'utf-8' });
|
|
131
|
+
const branchList = branches.split('\n').map(b => b.trim().replace(/^\*\s*/, '').replace(/^remotes\/origin\//, ''));
|
|
132
|
+
return branchList.includes(branchName);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 创建并切换到新分支
|
|
139
|
+
function createBranch(branchName) {
|
|
140
|
+
try {
|
|
141
|
+
// 检查分支是否已存在
|
|
142
|
+
if (branchExists(branchName)) {
|
|
143
|
+
error(`分支 ${branchName} 已存在!`);
|
|
144
|
+
const rl = readline.createInterface({
|
|
145
|
+
input: process.stdin,
|
|
146
|
+
output: process.stdout
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return new Promise((resolve, reject) => {
|
|
150
|
+
rl.question('是否切换到已存在的分支?(y/n): ', answer => {
|
|
151
|
+
rl.close();
|
|
152
|
+
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
|
153
|
+
try {
|
|
154
|
+
log(`切换到分支: ${branchName}`);
|
|
155
|
+
execSync(`git checkout ${branchName}`, { stdio: 'inherit' });
|
|
156
|
+
success(`已切换到分支: ${branchName}`);
|
|
157
|
+
resolve(true);
|
|
158
|
+
} catch (err) {
|
|
159
|
+
error(`切换分支失败: ${err.message}`);
|
|
160
|
+
reject(err);
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
log('已取消操作');
|
|
164
|
+
reject(new Error('用户取消'));
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 创建新分支
|
|
171
|
+
log(`创建新分支: ${branchName}`);
|
|
172
|
+
execSync(`git checkout -b ${branchName}`, { stdio: 'inherit' });
|
|
173
|
+
success(`已创建并切换到分支: ${branchName}`);
|
|
174
|
+
return Promise.resolve(true);
|
|
175
|
+
} catch (err) {
|
|
176
|
+
error(`创建分支失败: ${err.message}`);
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 主函数
|
|
182
|
+
async function main() {
|
|
183
|
+
try {
|
|
184
|
+
// 解析命令行参数
|
|
185
|
+
const args = process.argv.slice(2);
|
|
186
|
+
|
|
187
|
+
// 检查是否是 bug 类型
|
|
188
|
+
const isBug = args.includes('-b') || args.includes('--bug');
|
|
189
|
+
|
|
190
|
+
// 移除标志参数,获取需求标题
|
|
191
|
+
const titleArgs = args.filter(arg => arg !== '-b' && arg !== '--bug');
|
|
192
|
+
|
|
193
|
+
if (titleArgs.length === 0) {
|
|
194
|
+
console.log('\n用法:');
|
|
195
|
+
console.log(' create-branch <需求标题> # 创建 feature 分支');
|
|
196
|
+
console.log(' create-branch <需求标题> -b # 创建 hotFix 分支');
|
|
197
|
+
console.log(' create-branch <需求标题> --bug # 创建 hotFix 分支');
|
|
198
|
+
console.log('\n示例:');
|
|
199
|
+
console.log(' create-branch 用户登录功能');
|
|
200
|
+
console.log(' create-branch 修复登录bug -b');
|
|
201
|
+
console.log('\n别名:');
|
|
202
|
+
console.log(' cb <需求标题> [-b|--bug]');
|
|
203
|
+
process.exit(0);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const title = titleArgs.join(' ');
|
|
207
|
+
|
|
208
|
+
// 检查是否在 Git 仓库中
|
|
209
|
+
if (!isGitRepo()) {
|
|
210
|
+
error('当前目录不是 Git 仓库!');
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 读取或初始化用户配置
|
|
215
|
+
let config = readConfig();
|
|
216
|
+
if (!config || !config.workId || !config.name) {
|
|
217
|
+
config = await initUserInfo();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// 生成分支名
|
|
221
|
+
const branchName = generateBranchName(config.workId, config.name, title, isBug);
|
|
222
|
+
|
|
223
|
+
// 创建分支
|
|
224
|
+
await createBranch(branchName);
|
|
225
|
+
|
|
226
|
+
} catch (err) {
|
|
227
|
+
error(err.message);
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// 运行主函数
|
|
233
|
+
main();
|
|
234
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-branch-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "快速创建 Git 分支的工具,支持 feature 和 hotFix 分支类型",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-branch": "./index.js",
|
|
8
|
+
"cb": "./index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"git",
|
|
15
|
+
"branch",
|
|
16
|
+
"cli",
|
|
17
|
+
"automation"
|
|
18
|
+
],
|
|
19
|
+
"author": "",
|
|
20
|
+
"license": "ISC",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=12.0.0"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|