-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathgreset.js
More file actions
executable file
·151 lines (126 loc) · 7.14 KB
/
greset.js
File metadata and controls
executable file
·151 lines (126 loc) · 7.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env node
import { execSync } from 'child_process';
import chalk from 'chalk';
function greset() {
const args = process.argv.slice(2);
// Handle help command
if (args.includes('--help') || args.includes('-h')) {
console.log(chalk.magenta.bold('\n↩️ greset - Reset Repository State\n'));
console.log(chalk.cyan('Purpose:'), 'Reset current branch head to specified state, undoing commits or staging changes with precision control.\n');
console.log(chalk.cyan('Command:'), chalk.white('greset [options] [commit]\n'));
console.log(chalk.cyan('Parameters:'));
console.log(' ' + chalk.white('[commit]') + ' - Target commit hash, tag, or reference (default: HEAD)\n');
console.log(chalk.cyan('Essential Options:'));
console.log(' ' + chalk.green('--soft') + ' - Reset HEAD only, keep index and working tree');
console.log(' ' + chalk.green('--mixed') + ' - Reset HEAD and index, keep working tree (default)');
console.log(' ' + chalk.green('--hard') + ' - Reset HEAD, index, and working tree');
console.log(' ' + chalk.green('--merge') + ' - Reset but keep local changes in working tree');
console.log(' ' + chalk.green('--keep') + ' - Reset but abort if changes would be lost');
console.log(' ' + chalk.green('-q, --quiet') + ' - Operate quietly, suppress output');
console.log(' ' + chalk.green('--') + ' - Separate options from file paths');
console.log(' ' + chalk.green('-h, --help') + ' - Show detailed help information\n');
console.log(chalk.cyan('File-Specific Reset:'));
console.log(' ' + chalk.green('-- <file>...') + ' - Reset specific files to HEAD state');
console.log(' ' + chalk.green('-- <pathspec>...') + ' - Reset files matching pattern\n');
console.log(chalk.cyan('Advanced Options:'));
console.log(' ' + chalk.green('--recurse-submodules') + ' - Also reset submodules');
console.log(' ' + chalk.green('--no-recurse-submodules') + ' - Don\'t reset submodules');
console.log(' ' + chalk.green('--pathspec-from-file=<f>') + '- Read pathspec from file');
console.log(' ' + chalk.green('--pathspec-file-nul') + ' - Pathspec file is NUL separated\n');
console.log(chalk.cyan('Common Use Cases:'));
console.log(chalk.white(' greset') + ' # Unstage all staged changes');
console.log(chalk.white(' greset --soft HEAD~1') + ' # Undo last commit, keep changes staged');
console.log(chalk.white(' greset --mixed HEAD~1') + ' # Undo last commit, unstage changes');
console.log(chalk.white(' greset --hard HEAD~3') + ' # Undo last 3 commits completely');
console.log(chalk.white(' greset -- file.txt') + ' # Reset specific file to HEAD');
console.log(chalk.white(' greset --hard origin/main') + ' # Reset to match remote branch');
console.log(chalk.white(' greset --merge') + ' # Reset but preserve local changes\n');
console.log(chalk.cyan('💡 Reset Types Explained:'));
console.log(' ' + chalk.yellow('--soft') + ' - Only move HEAD pointer (commits become unstaged)');
console.log(' ' + chalk.yellow('--mixed') + ' - Move HEAD and reset index (commits become untracked)');
console.log(' ' + chalk.yellow('--hard') + ' - Reset everything (⚠️ destroys uncommitted work)');
console.log(' ' + chalk.yellow('--merge') + ' - Smart reset that preserves uncommitted changes');
console.log(' ' + chalk.yellow('--keep') + ' - Safe reset that aborts if data would be lost\n');
console.log(chalk.cyan('⚠️ Safety Warnings:'));
console.log(' • ' + chalk.red('--hard') + ' permanently deletes uncommitted changes');
console.log(' • Always check ' + chalk.yellow('git status') + ' before hard reset');
console.log(' • Consider ' + chalk.yellow('git stash') + ' to save work before reset');
console.log(' • Use ' + chalk.yellow('--soft') + ' or ' + chalk.yellow('--mixed') + ' for safer operations');
console.log(' • ' + chalk.yellow('git reflog') + ' can help recover lost commits');
console.log('\n' + chalk.gray('═'.repeat(60)));
process.exit(0);
}
try {
// Build command
let command = 'git reset';
// Parse arguments to detect mode and files
const hasFiles = args.includes('--');
const fileIndex = args.indexOf('--');
const beforeFiles = fileIndex !== -1 ? args.slice(0, fileIndex) : args;
const files = fileIndex !== -1 ? args.slice(fileIndex + 1) : [];
// Add parsed arguments (excluding -h/--help)
const validArgs = beforeFiles.filter(arg => !['--help', '-h'].includes(arg));
if (validArgs.length > 0) {
command += ` ${validArgs.join(' ')}`;
}
// Add file separator and files if present
if (hasFiles) {
command += ' --';
if (files.length > 0) {
command += ` ${files.join(' ')}`;
}
}
// Show what we're about to do
console.log(chalk.blue('🔄 Executing:'), chalk.white(command));
// Execute the git command
const output = execSync(command, {
cwd: process.cwd(),
encoding: 'utf8',
stdio: 'pipe'
});
// Show success message with output
if (output.trim()) {
console.log(chalk.green('✅ Reset completed:'));
console.log(output.trim());
} else {
console.log(chalk.green('✅ Reset completed successfully'));
}
// Show current status after reset for context
try {
const statusOutput = execSync('git status --porcelain', {
cwd: process.cwd(),
encoding: 'utf8',
stdio: 'pipe'
});
if (statusOutput.trim()) {
console.log(chalk.yellow('\n📋 Repository status after reset:'));
const status = execSync('git status -s', {
cwd: process.cwd(),
encoding: 'utf8'
});
console.log(status.trim());
} else {
console.log(chalk.green('\n✨ Working tree is clean after reset'));
}
} catch (statusError) {
// Status check failed, but reset succeeded
}
} catch (error) {
console.error(chalk.red('❌ Reset failed:'), error.message.trim());
// Provide helpful error context
if (error.message.includes('not a git repository')) {
console.log(chalk.yellow('💡 Make sure you\'re in a Git repository directory'));
} else if (error.message.includes('ambiguous argument')) {
console.log(chalk.yellow('💡 The specified commit reference doesn\'t exist'));
console.log(chalk.yellow(' Use: git log --oneline to see available commits'));
} else if (error.message.includes('pathspec') && error.message.includes('did not match')) {
console.log(chalk.yellow('💡 The specified file path doesn\'t exist'));
console.log(chalk.yellow(' Use: git ls-files to see tracked files'));
} else if (error.message.includes('fatal: Could not reset index file')) {
console.log(chalk.yellow('💡 Index is corrupted or locked'));
console.log(chalk.yellow(' Try: rm .git/index.lock'));
}
process.exit(1);
}
}
greset();