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.
Files changed (3) hide show
  1. package/README.md +105 -0
  2. package/index.js +234 -0
  3. 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
+