gittable 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 (51) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +459 -0
  3. package/cli.js +342 -0
  4. package/commands/add.js +159 -0
  5. package/commands/blame.js +33 -0
  6. package/commands/branch.js +234 -0
  7. package/commands/checkout.js +43 -0
  8. package/commands/cherry-pick.js +104 -0
  9. package/commands/clean.js +71 -0
  10. package/commands/clone.js +76 -0
  11. package/commands/commit.js +82 -0
  12. package/commands/config.js +171 -0
  13. package/commands/diff.js +30 -0
  14. package/commands/fetch.js +76 -0
  15. package/commands/grep.js +42 -0
  16. package/commands/init.js +45 -0
  17. package/commands/log.js +38 -0
  18. package/commands/merge.js +69 -0
  19. package/commands/mv.js +40 -0
  20. package/commands/pull.js +74 -0
  21. package/commands/push.js +97 -0
  22. package/commands/rebase.js +134 -0
  23. package/commands/remote.js +236 -0
  24. package/commands/restore.js +76 -0
  25. package/commands/revert.js +63 -0
  26. package/commands/rm.js +57 -0
  27. package/commands/show.js +47 -0
  28. package/commands/stash.js +201 -0
  29. package/commands/status.js +21 -0
  30. package/commands/sync.js +98 -0
  31. package/commands/tag.js +153 -0
  32. package/commands/undo.js +200 -0
  33. package/commands/uninit.js +57 -0
  34. package/index.d.ts +56 -0
  35. package/index.js +55 -0
  36. package/lib/commit/build-commit.js +64 -0
  37. package/lib/commit/get-previous-commit.js +15 -0
  38. package/lib/commit/questions.js +226 -0
  39. package/lib/config/read-config-file.js +54 -0
  40. package/lib/git/exec.js +222 -0
  41. package/lib/ui/ascii.js +154 -0
  42. package/lib/ui/banner.js +80 -0
  43. package/lib/ui/status-display.js +90 -0
  44. package/lib/ui/table.js +76 -0
  45. package/lib/utils/email-prompt.js +62 -0
  46. package/lib/utils/logger.js +47 -0
  47. package/lib/utils/spinner.js +57 -0
  48. package/lib/utils/terminal-link.js +55 -0
  49. package/lib/versions.js +17 -0
  50. package/package.json +73 -0
  51. package/standalone.js +24 -0
@@ -0,0 +1,134 @@
1
+ const clack = require('@clack/prompts');
2
+ const chalk = require('chalk');
3
+ const { execGit, getBranches, getCurrentBranch } = require('../lib/git/exec');
4
+ const { showBanner } = require('../lib/ui/banner');
5
+
6
+ module.exports = async (args) => {
7
+ showBanner('REBASE');
8
+ console.log(`${chalk.gray('├')} ${chalk.cyan.bold('Rebase')}`);
9
+
10
+ const currentBranch = getCurrentBranch();
11
+ const branches = getBranches();
12
+
13
+ let targetBranch = args[0];
14
+
15
+ if (!targetBranch) {
16
+ // Check if TTY is available for interactive prompts
17
+ if (!process.stdin.isTTY) {
18
+ clack.cancel(chalk.red('Interactive mode required'));
19
+ console.log(chalk.yellow('This command requires interactive input.'));
20
+ console.log(chalk.gray('Please provide a branch name: gittable rebase <branch>'));
21
+ process.exit(1);
22
+ }
23
+
24
+ const options = branches.local
25
+ .filter((branch) => !branch.current)
26
+ .map((branch) => ({
27
+ value: branch.name,
28
+ label: branch.name,
29
+ }));
30
+
31
+ // Add remote branches option
32
+ options.push({
33
+ value: '__remote__',
34
+ label: chalk.dim('Remote branch...'),
35
+ });
36
+
37
+ if (options.length === 0) {
38
+ clack.cancel(chalk.yellow('No branches to rebase onto'));
39
+ return;
40
+ }
41
+
42
+ targetBranch = await clack.select({
43
+ message: chalk.cyan('Select branch to rebase onto:'),
44
+ options,
45
+ });
46
+
47
+ if (clack.isCancel(targetBranch)) {
48
+ clack.cancel(chalk.yellow('Cancelled'));
49
+ return;
50
+ }
51
+
52
+ if (targetBranch === '__remote__') {
53
+ targetBranch = await clack.text({
54
+ message: chalk.cyan('Remote branch (e.g., origin/main):'),
55
+ placeholder: 'origin/main',
56
+ });
57
+
58
+ if (clack.isCancel(targetBranch)) {
59
+ clack.cancel(chalk.yellow('Cancelled'));
60
+ return;
61
+ }
62
+ }
63
+ }
64
+
65
+ const interactive = args.includes('--interactive') || args.includes('-i');
66
+ const continueRebase = args.includes('--continue');
67
+ const abortRebase = args.includes('--abort');
68
+
69
+ if (continueRebase) {
70
+ const spinner = clack.spinner();
71
+ spinner.start('Continuing rebase');
72
+ const result = execGit('rebase --continue', { silent: false });
73
+ spinner.stop();
74
+
75
+ if (result.success) {
76
+ clack.outro(chalk.green.bold('Rebase continued'));
77
+ } else {
78
+ clack.cancel(chalk.red('Rebase continue failed'));
79
+ console.error(result.error);
80
+ process.exit(1);
81
+ }
82
+ return;
83
+ }
84
+
85
+ if (abortRebase) {
86
+ if (!process.stdin.isTTY) {
87
+ clack.cancel(chalk.red('Interactive mode required'));
88
+ console.log(chalk.yellow('This command requires interactive confirmation.'));
89
+ process.exit(1);
90
+ }
91
+
92
+ const confirm = await clack.confirm({
93
+ message: chalk.yellow('Abort rebase? This will lose any rebase progress.'),
94
+ initialValue: false,
95
+ });
96
+
97
+ if (clack.isCancel(confirm) || !confirm) {
98
+ clack.cancel(chalk.yellow('Cancelled'));
99
+ return;
100
+ }
101
+
102
+ const spinner = clack.spinner();
103
+ spinner.start('Aborting rebase');
104
+ const result = execGit('rebase --abort', { silent: true });
105
+ spinner.stop();
106
+
107
+ if (result.success) {
108
+ clack.outro(chalk.green.bold('Rebase aborted'));
109
+ } else {
110
+ clack.cancel(chalk.red('Failed to abort rebase'));
111
+ console.error(result.error);
112
+ process.exit(1);
113
+ }
114
+ return;
115
+ }
116
+
117
+ const spinner = clack.spinner();
118
+ spinner.start(`Rebasing ${currentBranch} onto ${targetBranch}`);
119
+
120
+ const command = interactive ? `rebase --interactive ${targetBranch}` : `rebase ${targetBranch}`;
121
+ const result = execGit(command, { silent: false });
122
+ spinner.stop();
123
+
124
+ if (result.success) {
125
+ clack.outro(chalk.green.bold('Rebase completed'));
126
+ } else {
127
+ clack.cancel(chalk.red('Rebase failed'));
128
+ console.error(result.error);
129
+ console.log(chalk.yellow('\nYou may need to resolve conflicts manually'));
130
+ console.log(chalk.gray('Use "gittable rebase --continue" to continue after resolving'));
131
+ console.log(chalk.gray('Use "gittable rebase --abort" to abort the rebase'));
132
+ process.exit(1);
133
+ }
134
+ };
@@ -0,0 +1,236 @@
1
+ const clack = require('@clack/prompts');
2
+ const chalk = require('chalk');
3
+ const { execGit } = require('../lib/git/exec');
4
+ const { createTable } = require('../lib/ui/table');
5
+ const { showBanner } = require('../lib/ui/banner');
6
+
7
+ const listRemotes = () => {
8
+ const result = execGit('remote -v', { silent: true });
9
+ if (!result.success) {
10
+ console.log(chalk.dim('No remotes found'));
11
+ return;
12
+ }
13
+
14
+ const lines = result.output.trim().split('\n').filter(Boolean);
15
+ const remotes = {};
16
+
17
+ for (const line of lines) {
18
+ const [name, url, type] = line.split(/\s+/);
19
+ if (!remotes[name]) {
20
+ remotes[name] = { name, url, fetch: '', push: '' };
21
+ }
22
+ if (type === '(fetch)') {
23
+ remotes[name].fetch = url;
24
+ } else if (type === '(push)') {
25
+ remotes[name].push = url;
26
+ }
27
+ }
28
+
29
+ const rows = Object.values(remotes).map((remote) => [
30
+ remote.name,
31
+ remote.fetch || remote.push,
32
+ remote.fetch && remote.push && remote.fetch !== remote.push ? chalk.yellow('different') : '',
33
+ ]);
34
+
35
+ console.log(`\n${createTable(['Remote', 'URL', 'Note'], rows)}`);
36
+ };
37
+
38
+ const addRemote = async (name, url) => {
39
+ if (!name) {
40
+ name = await clack.text({
41
+ message: chalk.cyan('Remote name:'),
42
+ placeholder: 'origin',
43
+ });
44
+
45
+ if (clack.isCancel(name)) {
46
+ clack.cancel(chalk.yellow('Cancelled'));
47
+ return false;
48
+ }
49
+ }
50
+
51
+ if (!url) {
52
+ url = await clack.text({
53
+ message: chalk.cyan('Remote URL:'),
54
+ placeholder: 'https://github.com/user/repo.git',
55
+ });
56
+
57
+ if (clack.isCancel(url)) {
58
+ clack.cancel(chalk.yellow('Cancelled'));
59
+ return false;
60
+ }
61
+ }
62
+
63
+ const spinner = clack.spinner();
64
+ spinner.start(`Adding remote ${name}`);
65
+
66
+ const result = execGit(`remote add ${name} ${url}`, { silent: true });
67
+ spinner.stop();
68
+
69
+ if (result.success) {
70
+ console.log(chalk.green(`✓ Remote ${name} added`));
71
+ return true;
72
+ } else {
73
+ clack.cancel(chalk.red('Failed to add remote'));
74
+ console.error(result.error);
75
+ return false;
76
+ }
77
+ };
78
+
79
+ const removeRemote = async (name) => {
80
+ if (!name) {
81
+ name = await clack.text({
82
+ message: chalk.cyan('Remote name to remove:'),
83
+ placeholder: 'origin',
84
+ });
85
+
86
+ if (clack.isCancel(name)) {
87
+ clack.cancel(chalk.yellow('Cancelled'));
88
+ return;
89
+ }
90
+ }
91
+
92
+ const confirm = await clack.confirm({
93
+ message: chalk.yellow(`Remove remote ${name}?`),
94
+ initialValue: false,
95
+ });
96
+
97
+ if (clack.isCancel(confirm) || !confirm) {
98
+ clack.cancel(chalk.yellow('Cancelled'));
99
+ return;
100
+ }
101
+
102
+ const spinner = clack.spinner();
103
+ spinner.start(`Removing remote ${name}`);
104
+
105
+ const result = execGit(`remote remove ${name}`, { silent: true });
106
+ spinner.stop();
107
+
108
+ if (result.success) {
109
+ clack.outro(chalk.green.bold(`Remote ${name} removed`));
110
+ } else {
111
+ clack.cancel(chalk.red('Failed to remove remote'));
112
+ console.error(result.error);
113
+ process.exit(1);
114
+ }
115
+ };
116
+
117
+ const renameRemote = async (oldName, newName) => {
118
+ if (!oldName) {
119
+ oldName = await clack.text({
120
+ message: chalk.cyan('Current remote name:'),
121
+ placeholder: 'origin',
122
+ });
123
+
124
+ if (clack.isCancel(oldName)) {
125
+ clack.cancel(chalk.yellow('Cancelled'));
126
+ return;
127
+ }
128
+ }
129
+
130
+ if (!newName) {
131
+ newName = await clack.text({
132
+ message: chalk.cyan('New remote name:'),
133
+ placeholder: 'upstream',
134
+ });
135
+
136
+ if (clack.isCancel(newName)) {
137
+ clack.cancel(chalk.yellow('Cancelled'));
138
+ return;
139
+ }
140
+ }
141
+
142
+ const spinner = clack.spinner();
143
+ spinner.start(`Renaming remote ${oldName} to ${newName}`);
144
+
145
+ const result = execGit(`remote rename ${oldName} ${newName}`, { silent: true });
146
+ spinner.stop();
147
+
148
+ if (result.success) {
149
+ clack.outro(chalk.green.bold(`Remote renamed to ${newName}`));
150
+ } else {
151
+ clack.cancel(chalk.red('Failed to rename remote'));
152
+ console.error(result.error);
153
+ process.exit(1);
154
+ }
155
+ };
156
+
157
+ module.exports = async (args) => {
158
+ const action = args[0];
159
+
160
+ // If no action provided, show interactive menu
161
+ if (!action) {
162
+ showBanner('REMOTE');
163
+
164
+ // Check if TTY is available for interactive prompts
165
+ if (!process.stdin.isTTY) {
166
+ clack.cancel(chalk.red('Interactive mode required'));
167
+ console.log(chalk.yellow('This command requires interactive input.'));
168
+ console.log(chalk.gray('Available actions:'));
169
+ console.log(chalk.gray(' - gittable remote list (or ls)'));
170
+ console.log(chalk.gray(' - gittable remote add <name> <url>'));
171
+ console.log(chalk.gray(' - gittable remote remove <name> (or rm)'));
172
+ console.log(chalk.gray(' - gittable remote rename <old> <new> (or mv)'));
173
+ process.exit(1);
174
+ }
175
+
176
+ const selectedAction = await clack.select({
177
+ message: chalk.cyan('What would you like to do?'),
178
+ options: [
179
+ { value: 'list', label: chalk.cyan('List remotes') },
180
+ { value: 'add', label: chalk.green('Add remote') },
181
+ { value: 'remove', label: chalk.red('Remove remote') },
182
+ { value: 'rename', label: chalk.yellow('Rename remote') },
183
+ ],
184
+ });
185
+
186
+ if (clack.isCancel(selectedAction)) {
187
+ clack.cancel(chalk.yellow('Cancelled'));
188
+ return;
189
+ }
190
+
191
+ // Recursively call with the selected action
192
+ return module.exports([selectedAction, ...args.slice(1)]);
193
+ }
194
+
195
+ if (action === 'list' || action === 'ls') {
196
+ showBanner('REMOTE');
197
+ console.log(`${chalk.gray('├')} ${chalk.cyan.bold('Remote List')}`);
198
+ listRemotes();
199
+ clack.outro(chalk.green.bold('Done'));
200
+ return;
201
+ }
202
+
203
+ if (action === 'add') {
204
+ showBanner('REMOTE');
205
+ console.log(`${chalk.gray('├')} ${chalk.cyan.bold('Add Remote')}`);
206
+ await addRemote(args[1], args[2]);
207
+ return;
208
+ }
209
+
210
+ if (action === 'remove' || action === 'rm') {
211
+ showBanner('REMOTE');
212
+ console.log(`${chalk.gray('├')} ${chalk.cyan.bold('Remove Remote')}`);
213
+ await removeRemote(args[1]);
214
+ return;
215
+ }
216
+
217
+ if (action === 'rename' || action === 'mv') {
218
+ showBanner('REMOTE');
219
+ console.log(`${chalk.gray('├')} ${chalk.cyan.bold('Rename Remote')}`);
220
+ await renameRemote(args[1], args[2]);
221
+ return;
222
+ }
223
+
224
+ // Unknown action - show help
225
+ showBanner('REMOTE');
226
+ clack.cancel(chalk.red(`Unknown action: ${action}`));
227
+ console.log(chalk.yellow('\nAvailable actions:'));
228
+ console.log(chalk.cyan(' list, ls - List all remotes'));
229
+ console.log(chalk.cyan(' add - Add a new remote'));
230
+ console.log(chalk.cyan(' remove, rm - Remove a remote'));
231
+ console.log(chalk.cyan(' rename, mv - Rename a remote'));
232
+ process.exit(1);
233
+ };
234
+
235
+ // Export addRemote for use in other commands
236
+ module.exports.addRemote = addRemote;
@@ -0,0 +1,76 @@
1
+ const clack = require('@clack/prompts');
2
+ const chalk = require('chalk');
3
+ const { execGit, getStatus } = require('../lib/git/exec');
4
+ const { showBanner } = require('../lib/ui/banner');
5
+
6
+ module.exports = async (args) => {
7
+ showBanner('RESTORE');
8
+ console.log(`${chalk.gray('├')} ${chalk.cyan.bold('Restore Files')}`);
9
+
10
+ const staged = args.includes('--staged') || args.includes('--cached');
11
+ const source = args.find((arg) => arg.startsWith('--source='))?.split('=')[1];
12
+ const files = args.filter((arg) => !arg.startsWith('--'));
13
+
14
+ if (files.length === 0) {
15
+ // Check if TTY is available for interactive prompts
16
+ if (!process.stdin.isTTY) {
17
+ clack.cancel(chalk.red('Interactive mode required'));
18
+ console.log(chalk.yellow('This command requires interactive input.'));
19
+ console.log(chalk.gray('Available options:'));
20
+ console.log(chalk.gray(' - gittable restore <file1> <file2> ...'));
21
+ console.log(chalk.gray(' - gittable restore --staged <file1> <file2> ...'));
22
+ process.exit(1);
23
+ }
24
+
25
+ // Interactive mode: show files that can be restored
26
+ const status = getStatus();
27
+ if (!status) {
28
+ clack.cancel(chalk.red('Failed to get repository status'));
29
+ process.exit(1);
30
+ }
31
+
32
+ const availableFiles = staged
33
+ ? status.staged.map((f) => ({ value: f.file, label: chalk.yellow(`M ${f.file}`) }))
34
+ : status.unstaged.map((f) => ({ value: f.file, label: chalk.yellow(`M ${f.file}`) }));
35
+
36
+ if (availableFiles.length === 0) {
37
+ clack.cancel(chalk.yellow(`No ${staged ? 'staged' : 'unstaged'} files to restore`));
38
+ return;
39
+ }
40
+
41
+ const selected = await clack.multiselect({
42
+ message: chalk.cyan(`Select files to restore${staged ? ' (from staging)' : ''}:`),
43
+ options: availableFiles,
44
+ });
45
+
46
+ if (clack.isCancel(selected)) {
47
+ clack.cancel(chalk.yellow('Cancelled'));
48
+ return;
49
+ }
50
+
51
+ files.push(...selected);
52
+ }
53
+
54
+ const spinner = clack.spinner();
55
+ spinner.start(`Restoring ${files.length} file(s)`);
56
+
57
+ let command = 'restore';
58
+ if (staged) {
59
+ command += ' --staged';
60
+ }
61
+ if (source) {
62
+ command += ` --source=${source}`;
63
+ }
64
+ command += ` -- ${files.join(' ')}`;
65
+
66
+ const result = execGit(command, { silent: false });
67
+ spinner.stop();
68
+
69
+ if (result.success) {
70
+ clack.outro(chalk.green.bold(`Restored ${files.length} file(s)`));
71
+ } else {
72
+ clack.cancel(chalk.red('Failed to restore files'));
73
+ console.error(result.error);
74
+ process.exit(1);
75
+ }
76
+ };
@@ -0,0 +1,63 @@
1
+ const clack = require('@clack/prompts');
2
+ const chalk = require('chalk');
3
+ const { execGit, getLog } = require('../lib/git/exec');
4
+ const { showBanner } = require('../lib/ui/banner');
5
+
6
+ module.exports = async (args) => {
7
+ showBanner('REVERT');
8
+ console.log(`${chalk.gray('├')} ${chalk.cyan.bold('Revert Commit')}`);
9
+
10
+ let commit = args[0];
11
+ const noCommit = args.includes('--no-commit') || args.includes('-n');
12
+
13
+ if (!commit) {
14
+ if (!process.stdin.isTTY) {
15
+ clack.cancel(chalk.red('Interactive mode required'));
16
+ console.log(chalk.yellow('This command requires interactive input.'));
17
+ console.log(chalk.gray('Please provide a commit hash: gittable revert <commit>'));
18
+ process.exit(1);
19
+ }
20
+
21
+ const commits = getLog(10, '%h|%s');
22
+ if (commits.length === 0) {
23
+ clack.cancel(chalk.yellow('No commits found'));
24
+ return;
25
+ }
26
+
27
+ const options = commits.map((c) => ({
28
+ value: c.hash,
29
+ label: `${c.hash} - ${c.message}`,
30
+ }));
31
+
32
+ commit = await clack.select({
33
+ message: chalk.cyan('Select commit to revert:'),
34
+ options,
35
+ });
36
+
37
+ if (clack.isCancel(commit)) {
38
+ clack.cancel(chalk.yellow('Cancelled'));
39
+ return;
40
+ }
41
+ }
42
+
43
+ const spinner = clack.spinner();
44
+ spinner.start(`Reverting commit ${commit}`);
45
+
46
+ let command = 'revert';
47
+ if (noCommit) {
48
+ command += ' --no-commit';
49
+ }
50
+ command += ` ${commit}`;
51
+
52
+ const result = execGit(command, { silent: false });
53
+ spinner.stop();
54
+
55
+ if (result.success) {
56
+ clack.outro(chalk.green.bold(`Reverted commit ${commit}`));
57
+ } else {
58
+ clack.cancel(chalk.red('Revert failed'));
59
+ console.error(result.error);
60
+ console.log(chalk.yellow('\nYou may need to resolve conflicts manually'));
61
+ process.exit(1);
62
+ }
63
+ };
package/commands/rm.js ADDED
@@ -0,0 +1,57 @@
1
+ const clack = require('@clack/prompts');
2
+ const chalk = require('chalk');
3
+ const { execGit } = require('../lib/git/exec');
4
+ const { showBanner } = require('../lib/ui/banner');
5
+
6
+ module.exports = async (args) => {
7
+ showBanner('RM');
8
+ console.log(`${chalk.gray('├')} ${chalk.cyan.bold('Remove Files')}`);
9
+
10
+ const files = args.filter((arg) => !arg.startsWith('--'));
11
+ const cached = args.includes('--cached') || args.includes('--staged');
12
+ const force = args.includes('--force') || args.includes('-f');
13
+ const recursive = args.includes('--recursive') || args.includes('-r');
14
+
15
+ if (files.length === 0) {
16
+ clack.cancel(chalk.yellow('No files specified'));
17
+ return;
18
+ }
19
+
20
+ if (!force) {
21
+ const confirm = await clack.confirm({
22
+ message: chalk.yellow(`Remove ${files.length} file(s) from git?`),
23
+ initialValue: false,
24
+ });
25
+
26
+ if (clack.isCancel(confirm) || !confirm) {
27
+ clack.cancel(chalk.yellow('Cancelled'));
28
+ return;
29
+ }
30
+ }
31
+
32
+ const spinner = clack.spinner();
33
+ spinner.start(`Removing ${files.length} file(s)`);
34
+
35
+ let command = 'rm';
36
+ if (cached) {
37
+ command += ' --cached';
38
+ }
39
+ if (force) {
40
+ command += ' --force';
41
+ }
42
+ if (recursive) {
43
+ command += ' --recursive';
44
+ }
45
+ command += ` ${files.join(' ')}`;
46
+
47
+ const result = execGit(command, { silent: false });
48
+ spinner.stop();
49
+
50
+ if (result.success) {
51
+ clack.outro(chalk.green.bold(`Removed ${files.length} file(s)`));
52
+ } else {
53
+ clack.cancel(chalk.red('Failed to remove files'));
54
+ console.error(result.error);
55
+ process.exit(1);
56
+ }
57
+ };
@@ -0,0 +1,47 @@
1
+ const clack = require('@clack/prompts');
2
+ const chalk = require('chalk');
3
+ const { execGit } = require('../lib/git/exec');
4
+ const { showBanner } = require('../lib/ui/banner');
5
+
6
+ module.exports = async (args) => {
7
+ showBanner('SHOW');
8
+ console.log(`${chalk.gray('├')} ${chalk.cyan.bold('Show Commit')}`);
9
+
10
+ const commit = args[0] || 'HEAD';
11
+
12
+ // Check if commit exists (for HEAD or any commit)
13
+ const checkResult = execGit(`rev-parse --verify ${commit}`, { silent: true });
14
+ if (!checkResult.success) {
15
+ clack.cancel(chalk.red('Failed to show commit'));
16
+ if (commit === 'HEAD') {
17
+ console.log(chalk.yellow('No commits found in repository'));
18
+ console.log(chalk.gray('Make at least one commit before using show'));
19
+ } else {
20
+ console.error(chalk.red(`Commit ${commit} does not exist`));
21
+ }
22
+ process.exit(1);
23
+ }
24
+
25
+ const stat = args.includes('--stat') || args.includes('-s');
26
+ const nameOnly = args.includes('--name-only') || args.includes('--name-status');
27
+
28
+ let command = 'show';
29
+ if (stat) {
30
+ command += ' --stat';
31
+ } else if (nameOnly) {
32
+ command += ' --name-status';
33
+ } else {
34
+ command += ' --format=fuller';
35
+ }
36
+ command += ` ${commit}`;
37
+
38
+ const result = execGit(command, { silent: false });
39
+
40
+ if (!result.success) {
41
+ clack.cancel(chalk.red('Failed to show commit'));
42
+ console.error(result.error);
43
+ process.exit(1);
44
+ }
45
+
46
+ clack.outro(chalk.green.bold('Done'));
47
+ };