gent-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 +316 -0
- package/commands-reference.js +116 -0
- package/package.json +43 -0
- package/src/commands/add.js +88 -0
- package/src/commands/branch.js +115 -0
- package/src/commands/checkout.js +74 -0
- package/src/commands/commit.js +108 -0
- package/src/commands/init.js +140 -0
- package/src/commands/log.js +92 -0
- package/src/commands/status.js +167 -0
- package/src/index.js +104 -0
- package/src/utils/constants.js +41 -0
- package/src/utils/fileSystem.js +188 -0
- package/src/utils/helpers.js +130 -0
package/README.md
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
# Gent CLI - A Git-like Version Control System
|
|
2
|
+
|
|
3
|
+
š **Gent** is a lightweight, Git-inspired version control CLI tool built with Node.js. It provides essential version control features with an intuitive command-line interface.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Repository Initialization** - Set up new Gent repositories with custom configuration
|
|
8
|
+
- **File Staging** - Add files to staging area before committing
|
|
9
|
+
- **Commit Management** - Record changes with descriptive messages
|
|
10
|
+
- **Branch Operations** - Create, switch, and manage branches
|
|
11
|
+
- **Status Tracking** - View working tree status and changes
|
|
12
|
+
- **Commit History** - Browse commit logs with detailed information
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Navigate to the CLI directory
|
|
18
|
+
cd apps/Cli
|
|
19
|
+
|
|
20
|
+
# Install dependencies
|
|
21
|
+
npm install
|
|
22
|
+
|
|
23
|
+
# Link globally (optional)
|
|
24
|
+
npm link
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### Initialize a Repository
|
|
30
|
+
|
|
31
|
+
Create a new Gent repository in the current directory:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
gent init
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
With default configuration (skip prompts):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
gent init -y
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Check Status
|
|
44
|
+
|
|
45
|
+
View the current state of your working tree:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
gent status
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Short format:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
gent status -s
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Stage Files
|
|
58
|
+
|
|
59
|
+
Add files to the staging area:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Add specific files
|
|
63
|
+
gent add file1.js file2.js
|
|
64
|
+
|
|
65
|
+
# Add all files
|
|
66
|
+
gent add --all
|
|
67
|
+
gent add .
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Commit Changes
|
|
71
|
+
|
|
72
|
+
Record changes to the repository:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# With inline message
|
|
76
|
+
gent commit -m "Your commit message"
|
|
77
|
+
|
|
78
|
+
# Interactive (will prompt for message)
|
|
79
|
+
gent commit
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Auto-stage all modified files:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
gent commit -a -m "Commit all changes"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### View Commit History
|
|
89
|
+
|
|
90
|
+
Display commit logs:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Show last 10 commits (default)
|
|
94
|
+
gent log
|
|
95
|
+
|
|
96
|
+
# Show specific number of commits
|
|
97
|
+
gent log -n 5
|
|
98
|
+
|
|
99
|
+
# Compact oneline format
|
|
100
|
+
gent log --oneline
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Branch Management
|
|
104
|
+
|
|
105
|
+
List all branches:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
gent branch
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Create a new branch:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
gent branch feature-name
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Delete a branch:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
gent branch -d branch-name
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Switch Branches
|
|
124
|
+
|
|
125
|
+
Switch to an existing branch:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
gent checkout branch-name
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Create and switch to a new branch:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
gent checkout -b new-branch
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Project Structure
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
apps/Cli/
|
|
141
|
+
āāā src/
|
|
142
|
+
ā āāā index.js # Main entry point
|
|
143
|
+
ā āāā commands/ # Command implementations
|
|
144
|
+
ā ā āāā init.js # Initialize repository
|
|
145
|
+
ā ā āāā status.js # Show status
|
|
146
|
+
ā ā āāā add.js # Stage files
|
|
147
|
+
ā ā āāā commit.js # Create commits
|
|
148
|
+
ā ā āāā log.js # View history
|
|
149
|
+
ā ā āāā branch.js # Manage branches
|
|
150
|
+
ā ā āāā checkout.js # Switch branches
|
|
151
|
+
ā āāā utils/ # Utility modules
|
|
152
|
+
ā āāā constants.js # Application constants
|
|
153
|
+
ā āāā fileSystem.js # File operations
|
|
154
|
+
ā āāā helpers.js # Helper functions
|
|
155
|
+
āāā package.json # Dependencies and scripts
|
|
156
|
+
āāā README.md # Documentation
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Repository Structure
|
|
160
|
+
|
|
161
|
+
When you initialize a Gent repository, it creates a `.gent` directory:
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
.gent/
|
|
165
|
+
āāā config.json # Repository configuration
|
|
166
|
+
āāā staging.json # Staged files
|
|
167
|
+
āāā commits.json # Commit history
|
|
168
|
+
āāā HEAD # Current branch reference
|
|
169
|
+
āāā objects/ # File objects (future use)
|
|
170
|
+
āāā refs/ # Branch references
|
|
171
|
+
āāā heads/ # Branch pointers
|
|
172
|
+
āāā tags/ # Tag references
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Configuration
|
|
176
|
+
|
|
177
|
+
Gent stores configuration in `.gent/config.json`:
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"user": {
|
|
182
|
+
"name": "Your Name",
|
|
183
|
+
"email": "your.email@example.com"
|
|
184
|
+
},
|
|
185
|
+
"repository": {
|
|
186
|
+
"name": "project-name",
|
|
187
|
+
"description": "Project description",
|
|
188
|
+
"created": "2025-11-06T00:00:00.000Z"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Ignore Patterns
|
|
194
|
+
|
|
195
|
+
Create a `.gentignore` file to exclude files from tracking:
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
# Dependencies
|
|
199
|
+
node_modules/
|
|
200
|
+
|
|
201
|
+
# Build outputs
|
|
202
|
+
dist/
|
|
203
|
+
build/
|
|
204
|
+
|
|
205
|
+
# Environment files
|
|
206
|
+
.env
|
|
207
|
+
.env.local
|
|
208
|
+
|
|
209
|
+
# Logs
|
|
210
|
+
*.log
|
|
211
|
+
|
|
212
|
+
# OS files
|
|
213
|
+
.DS_Store
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Command Reference
|
|
217
|
+
|
|
218
|
+
| Command | Description | Options |
|
|
219
|
+
|---------|-------------|---------|
|
|
220
|
+
| `gent init` | Initialize repository | `-y, --yes` Skip prompts |
|
|
221
|
+
| `gent status` | Show working tree status | `-s, --short` Short format |
|
|
222
|
+
| `gent add <files>` | Stage files | `-A, --all` Stage all files |
|
|
223
|
+
| `gent commit` | Record changes | `-m <msg>` Message, `-a` Stage all |
|
|
224
|
+
| `gent log` | Show commit history | `-n <num>` Limit, `--oneline` Compact |
|
|
225
|
+
| `gent branch [name]` | Manage branches | `-d <name>` Delete, `-a` List all |
|
|
226
|
+
| `gent checkout <branch>` | Switch branches | `-b` Create new |
|
|
227
|
+
| `gent help [command]` | Show help | |
|
|
228
|
+
|
|
229
|
+
## Dependencies
|
|
230
|
+
|
|
231
|
+
- **commander** - CLI framework
|
|
232
|
+
- **chalk** - Terminal styling
|
|
233
|
+
- **inquirer** - Interactive prompts
|
|
234
|
+
- **ora** - Elegant terminal spinners
|
|
235
|
+
- **boxen** - Create boxes in terminal
|
|
236
|
+
- **date-fns** - Date formatting utilities
|
|
237
|
+
|
|
238
|
+
## Development
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
# Run locally
|
|
242
|
+
npm start
|
|
243
|
+
|
|
244
|
+
# Run specific command
|
|
245
|
+
node src/index.js init
|
|
246
|
+
node src/index.js status
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Examples
|
|
250
|
+
|
|
251
|
+
### Complete Workflow
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# Initialize repository
|
|
255
|
+
gent init
|
|
256
|
+
|
|
257
|
+
# Add some files
|
|
258
|
+
echo "console.log('Hello');" > app.js
|
|
259
|
+
gent add app.js
|
|
260
|
+
|
|
261
|
+
# Commit changes
|
|
262
|
+
gent commit -m "Initial commit"
|
|
263
|
+
|
|
264
|
+
# Create a feature branch
|
|
265
|
+
gent branch feature-login
|
|
266
|
+
gent checkout feature-login
|
|
267
|
+
|
|
268
|
+
# Make changes and commit
|
|
269
|
+
echo "// Login logic" >> app.js
|
|
270
|
+
gent add app.js
|
|
271
|
+
gent commit -m "Add login feature"
|
|
272
|
+
|
|
273
|
+
# View history
|
|
274
|
+
gent log
|
|
275
|
+
|
|
276
|
+
# Switch back to main
|
|
277
|
+
gent checkout main
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Error Handling
|
|
281
|
+
|
|
282
|
+
Gent provides clear error messages:
|
|
283
|
+
|
|
284
|
+
- **Not a gent repository** - Run `gent init` first
|
|
285
|
+
- **No changes to commit** - Stage files with `gent add`
|
|
286
|
+
- **Branch not found** - Check available branches with `gent branch`
|
|
287
|
+
|
|
288
|
+
## Best Practices
|
|
289
|
+
|
|
290
|
+
1. **Commit Often** - Make small, focused commits
|
|
291
|
+
2. **Write Clear Messages** - Describe what and why
|
|
292
|
+
3. **Use Branches** - Isolate features and experiments
|
|
293
|
+
4. **Check Status** - Review changes before committing
|
|
294
|
+
5. **Update .gentignore** - Exclude unnecessary files
|
|
295
|
+
|
|
296
|
+
## Future Enhancements
|
|
297
|
+
|
|
298
|
+
- [ ] Diff visualization
|
|
299
|
+
- [ ] Remote repository support
|
|
300
|
+
- [ ] Merge functionality
|
|
301
|
+
- [ ] Tag management
|
|
302
|
+
- [ ] Stash implementation
|
|
303
|
+
- [ ] File restoration
|
|
304
|
+
- [ ] Conflict resolution
|
|
305
|
+
|
|
306
|
+
## License
|
|
307
|
+
|
|
308
|
+
ISC
|
|
309
|
+
|
|
310
|
+
## Author
|
|
311
|
+
|
|
312
|
+
Built with ā¤ļø using Node.js
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
**Note**: Gent is a learning project and educational tool. For production use, consider established version control systems like Git.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gent CLI - Command Summary
|
|
5
|
+
* Quick reference for all available commands
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
const boxen = require('boxen');
|
|
10
|
+
|
|
11
|
+
const commands = [
|
|
12
|
+
{
|
|
13
|
+
name: 'init',
|
|
14
|
+
description: 'Initialize a new gent repository',
|
|
15
|
+
usage: 'gent init [options]',
|
|
16
|
+
options: ['-y, --yes Skip prompts and use defaults'],
|
|
17
|
+
examples: ['gent init', 'gent init -y']
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'status',
|
|
21
|
+
description: 'Show the working tree status',
|
|
22
|
+
usage: 'gent status [options]',
|
|
23
|
+
options: ['-s, --short Give output in short format'],
|
|
24
|
+
examples: ['gent status', 'gent status -s']
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'add',
|
|
28
|
+
description: 'Add file contents to the staging area',
|
|
29
|
+
usage: 'gent add <files...> [options]',
|
|
30
|
+
options: ['-A, --all Add all files'],
|
|
31
|
+
examples: ['gent add file.js', 'gent add .', 'gent add --all']
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'commit',
|
|
35
|
+
description: 'Record changes to the repository',
|
|
36
|
+
usage: 'gent commit [options]',
|
|
37
|
+
options: [
|
|
38
|
+
'-m, --message <message> Commit message',
|
|
39
|
+
'-a, --all Auto stage modified files'
|
|
40
|
+
],
|
|
41
|
+
examples: ['gent commit -m "Fix bug"', 'gent commit', 'gent commit -a -m "Update all"']
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'log',
|
|
45
|
+
description: 'Show commit logs',
|
|
46
|
+
usage: 'gent log [options]',
|
|
47
|
+
options: [
|
|
48
|
+
'-n, --number <count> Limit commits (default: 10)',
|
|
49
|
+
'--oneline Show each commit on one line'
|
|
50
|
+
],
|
|
51
|
+
examples: ['gent log', 'gent log -n 5', 'gent log --oneline']
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'branch',
|
|
55
|
+
description: 'List, create, or delete branches',
|
|
56
|
+
usage: 'gent branch [name] [options]',
|
|
57
|
+
options: [
|
|
58
|
+
'-d, --delete <name> Delete a branch',
|
|
59
|
+
'-a, --all List all branches'
|
|
60
|
+
],
|
|
61
|
+
examples: ['gent branch', 'gent branch feature-x', 'gent branch -d old-feature']
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'checkout',
|
|
65
|
+
description: 'Switch branches',
|
|
66
|
+
usage: 'gent checkout <branch> [options]',
|
|
67
|
+
options: ['-b, --create Create a new branch'],
|
|
68
|
+
examples: ['gent checkout main', 'gent checkout -b new-feature']
|
|
69
|
+
}
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
console.log(chalk.bold.cyan('\nš Gent CLI - Command Reference\n'));
|
|
73
|
+
|
|
74
|
+
commands.forEach((cmd, index) => {
|
|
75
|
+
console.log(chalk.yellow.bold(`${index + 1}. ${cmd.name.toUpperCase()}`));
|
|
76
|
+
console.log(chalk.white(` ${cmd.description}`));
|
|
77
|
+
console.log(chalk.gray(` Usage: ${cmd.usage}`));
|
|
78
|
+
|
|
79
|
+
if (cmd.options.length > 0) {
|
|
80
|
+
console.log(chalk.gray(' Options:'));
|
|
81
|
+
cmd.options.forEach(opt => {
|
|
82
|
+
console.log(chalk.gray(` ${opt}`));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log(chalk.cyan(' Examples:'));
|
|
87
|
+
cmd.examples.forEach(ex => {
|
|
88
|
+
console.log(chalk.green(` $ ${ex}`));
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
console.log();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const tips = `
|
|
95
|
+
${chalk.bold('š” Quick Tips:')}
|
|
96
|
+
|
|
97
|
+
${chalk.cyan('ā¢')} Always run ${chalk.yellow('gent init')} first in a new project
|
|
98
|
+
${chalk.cyan('ā¢')} Use ${chalk.yellow('gent status')} to see what changed
|
|
99
|
+
${chalk.cyan('ā¢')} Stage files with ${chalk.yellow('gent add')} before committing
|
|
100
|
+
${chalk.cyan('ā¢')} Create branches for new features
|
|
101
|
+
${chalk.cyan('ā¢')} Check ${chalk.yellow('gent log')} to view history
|
|
102
|
+
|
|
103
|
+
${chalk.bold('š Documentation:')}
|
|
104
|
+
${chalk.gray('⢠README.md - Complete documentation')}
|
|
105
|
+
${chalk.gray('⢠QUICKSTART.md - Quick start guide')}
|
|
106
|
+
${chalk.gray('⢠demo.sh - Interactive demo')}
|
|
107
|
+
`;
|
|
108
|
+
|
|
109
|
+
console.log(boxen(tips, {
|
|
110
|
+
padding: 1,
|
|
111
|
+
margin: 1,
|
|
112
|
+
borderStyle: 'round',
|
|
113
|
+
borderColor: 'cyan'
|
|
114
|
+
}));
|
|
115
|
+
|
|
116
|
+
console.log(chalk.gray('Run'), chalk.yellow('gent --help'), chalk.gray('for more information\n'));
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gent-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A Git-like version control CLI tool",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"gent": "./src/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node src/index.js",
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
12
|
+
"demo": "bash demo.sh",
|
|
13
|
+
"link": "npm link",
|
|
14
|
+
"unlink": "npm unlink"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"cli",
|
|
18
|
+
"version-control",
|
|
19
|
+
"git-like",
|
|
20
|
+
"gent"
|
|
21
|
+
],
|
|
22
|
+
"author": "Abdalrahman Kanawati <kanawatiabdalrahman@gmail.com>",
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/SaadShaya7/gent.git"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/SaadShaya7/gent#readme",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/SaadShaya7/gent/issues"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"commander": "^11.1.0",
|
|
34
|
+
"chalk": "^4.1.2",
|
|
35
|
+
"inquirer": "^8.2.5",
|
|
36
|
+
"ora": "^5.4.1",
|
|
37
|
+
"boxen": "^5.1.2",
|
|
38
|
+
"date-fns": "^2.30.0"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=14.0.0"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Add Command - Add file contents to the staging area
|
|
3
|
+
* Stages files for the next commit
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const ora = require('ora');
|
|
9
|
+
const { getGentPath, readJSON, writeJSON, pathExists, getAllFiles, getIgnorePatterns } = require('../utils/fileSystem');
|
|
10
|
+
const { STAGING_FILE } = require('../utils/constants');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Add files to staging area
|
|
14
|
+
* @param {Array} files - Files to add
|
|
15
|
+
* @param {Object} options - Command options
|
|
16
|
+
*/
|
|
17
|
+
async function add(files, options) {
|
|
18
|
+
const spinner = ora('Adding files to staging area...').start();
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const gentPath = await getGentPath();
|
|
22
|
+
const cwd = process.cwd();
|
|
23
|
+
const stagingPath = path.join(gentPath, STAGING_FILE);
|
|
24
|
+
|
|
25
|
+
// Read current staging area
|
|
26
|
+
const staging = await readJSON(stagingPath);
|
|
27
|
+
const stagedFiles = new Set(staging.files || []);
|
|
28
|
+
|
|
29
|
+
let filesToAdd = [];
|
|
30
|
+
|
|
31
|
+
// Handle --all option
|
|
32
|
+
if (options.all || files.includes('.') || files.includes('*')) {
|
|
33
|
+
spinner.text = 'Scanning for all files...';
|
|
34
|
+
const ignorePatterns = await getIgnorePatterns(cwd);
|
|
35
|
+
const allFiles = await getAllFiles(cwd, ignorePatterns);
|
|
36
|
+
filesToAdd = allFiles.map(f => path.relative(cwd, f));
|
|
37
|
+
} else {
|
|
38
|
+
// Add specified files
|
|
39
|
+
for (const file of files) {
|
|
40
|
+
const filePath = path.resolve(cwd, file);
|
|
41
|
+
|
|
42
|
+
if (!await pathExists(filePath)) {
|
|
43
|
+
spinner.warn(chalk.yellow(`Warning: File not found: ${file}`));
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const relativePath = path.relative(cwd, filePath);
|
|
48
|
+
filesToAdd.push(relativePath);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Add files to staging
|
|
53
|
+
let addedCount = 0;
|
|
54
|
+
for (const file of filesToAdd) {
|
|
55
|
+
if (!stagedFiles.has(file)) {
|
|
56
|
+
stagedFiles.add(file);
|
|
57
|
+
addedCount++;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Save staging area
|
|
62
|
+
staging.files = Array.from(stagedFiles);
|
|
63
|
+
await writeJSON(stagingPath, staging);
|
|
64
|
+
|
|
65
|
+
spinner.succeed(chalk.green(`ā Added ${addedCount} file(s) to staging area`));
|
|
66
|
+
|
|
67
|
+
if (addedCount > 0) {
|
|
68
|
+
console.log(chalk.gray('\nStaged files:'));
|
|
69
|
+
staging.files.forEach(file => {
|
|
70
|
+
console.log(chalk.green(` ${file}`));
|
|
71
|
+
});
|
|
72
|
+
console.log(chalk.cyan('\nā¹ Use "gent commit" to record your changes'));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
} catch (error) {
|
|
76
|
+
spinner.fail(chalk.red('Failed to add files'));
|
|
77
|
+
|
|
78
|
+
if (error.code === 'ENOENT' && error.message.includes('.gent')) {
|
|
79
|
+
console.error(chalk.red('\nError: Not a gent repository'));
|
|
80
|
+
console.log(chalk.yellow('ā¹ Run "gent init" to initialize a repository'));
|
|
81
|
+
} else {
|
|
82
|
+
console.error(chalk.red('\nError:'), error.message);
|
|
83
|
+
}
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = add;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branch Command - List, create, or delete branches
|
|
3
|
+
* Manages repository branches
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const { getGentPath, readJSON, writeJSON } = require('../utils/fileSystem');
|
|
9
|
+
const { COMMITS_FILE } = require('../utils/constants');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Manage branches
|
|
13
|
+
* @param {String} name - Branch name (optional)
|
|
14
|
+
* @param {Object} options - Command options
|
|
15
|
+
*/
|
|
16
|
+
async function branch(name, options) {
|
|
17
|
+
try {
|
|
18
|
+
const gentPath = await getGentPath();
|
|
19
|
+
const repository = await readJSON(path.join(gentPath, COMMITS_FILE));
|
|
20
|
+
|
|
21
|
+
// Delete branch
|
|
22
|
+
if (options.delete) {
|
|
23
|
+
await deleteBranch(options.delete, repository, gentPath);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Create new branch
|
|
28
|
+
if (name) {
|
|
29
|
+
await createBranch(name, repository, gentPath);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// List branches
|
|
34
|
+
listBranches(repository, options.all);
|
|
35
|
+
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (error.code === 'ENOENT' && error.message.includes('.gent')) {
|
|
38
|
+
console.error(chalk.red('Error: Not a gent repository'));
|
|
39
|
+
console.log(chalk.yellow('\nā¹ Run "gent init" to initialize a repository'));
|
|
40
|
+
} else {
|
|
41
|
+
console.error(chalk.red('Error:'), error.message);
|
|
42
|
+
}
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* List all branches
|
|
49
|
+
*/
|
|
50
|
+
function listBranches(repository, showAll) {
|
|
51
|
+
const branches = repository.branches || {};
|
|
52
|
+
const currentBranch = repository.currentBranch || 'main';
|
|
53
|
+
|
|
54
|
+
console.log(chalk.bold.cyan('\nBranches:\n'));
|
|
55
|
+
|
|
56
|
+
for (const [branch, commitHash] of Object.entries(branches)) {
|
|
57
|
+
const isCurrent = branch === currentBranch;
|
|
58
|
+
const prefix = isCurrent ? chalk.green('* ') : ' ';
|
|
59
|
+
const branchName = isCurrent ? chalk.green.bold(branch) : chalk.white(branch);
|
|
60
|
+
const commitInfo = commitHash ? chalk.gray(` (${commitHash.substring(0, 7)})`) : chalk.gray(' (no commits)');
|
|
61
|
+
|
|
62
|
+
console.log(`${prefix}${branchName}${commitInfo}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create a new branch
|
|
70
|
+
*/
|
|
71
|
+
async function createBranch(name, repository, gentPath) {
|
|
72
|
+
const branches = repository.branches || {};
|
|
73
|
+
|
|
74
|
+
if (branches.hasOwnProperty(name)) {
|
|
75
|
+
console.error(chalk.red(`Error: Branch '${name}' already exists`));
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Create branch from current HEAD
|
|
80
|
+
const currentCommit = branches[repository.currentBranch] || null;
|
|
81
|
+
branches[name] = currentCommit;
|
|
82
|
+
repository.branches = branches;
|
|
83
|
+
|
|
84
|
+
await writeJSON(path.join(gentPath, COMMITS_FILE), repository);
|
|
85
|
+
|
|
86
|
+
console.log(chalk.green(`ā Created branch '${name}'`));
|
|
87
|
+
console.log(chalk.gray(`Based on: ${repository.currentBranch}`));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Delete a branch
|
|
92
|
+
*/
|
|
93
|
+
async function deleteBranch(name, repository, gentPath) {
|
|
94
|
+
const branches = repository.branches || {};
|
|
95
|
+
|
|
96
|
+
if (!branches.hasOwnProperty(name)) {
|
|
97
|
+
console.error(chalk.red(`Error: Branch '${name}' not found`));
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (name === repository.currentBranch) {
|
|
102
|
+
console.error(chalk.red(`Error: Cannot delete current branch '${name}'`));
|
|
103
|
+
console.log(chalk.yellow('Switch to another branch first using "gent checkout <branch>"'));
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
delete branches[name];
|
|
108
|
+
repository.branches = branches;
|
|
109
|
+
|
|
110
|
+
await writeJSON(path.join(gentPath, COMMITS_FILE), repository);
|
|
111
|
+
|
|
112
|
+
console.log(chalk.green(`ā Deleted branch '${name}'`));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = branch;
|