@nemo-cli/git 0.1.3 → 0.1.4
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 +277 -0
- package/dist/index.js +103 -46
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -19,6 +19,8 @@ pnpm add @nemo-cli/git --global
|
|
|
19
19
|
- **Conventional Commits**: Interactive commit wizard with type/scope selection from your commitlint config
|
|
20
20
|
- **Smart Branch Management**: Advanced branch operations with merge status and time filtering
|
|
21
21
|
- **Ticket Auto-Detection**: Automatically extracts ticket numbers from branch names for commit messages
|
|
22
|
+
- **Interactive Commit Navigator**: Enhanced `ng blame` for browsing file history with full diff support
|
|
23
|
+
- **Visual History Viewer**: Beautiful `ng hist` command with interactive graph display and keyboard navigation
|
|
22
24
|
|
|
23
25
|
## Usage
|
|
24
26
|
|
|
@@ -35,6 +37,8 @@ ng <command> -h
|
|
|
35
37
|
# Example:
|
|
36
38
|
ng commit -h
|
|
37
39
|
ng branch -h
|
|
40
|
+
ng blame -h
|
|
41
|
+
ng hist -h
|
|
38
42
|
```
|
|
39
43
|
|
|
40
44
|
---
|
|
@@ -239,6 +243,180 @@ ng merge -r
|
|
|
239
243
|
|
|
240
244
|
---
|
|
241
245
|
|
|
246
|
+
### Interactive Commit Navigator (`ng blame`)
|
|
247
|
+
|
|
248
|
+
Browse file commit history with full diff support and interactive navigation.
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
# View commit history for a file
|
|
252
|
+
ng blame <file-path>
|
|
253
|
+
|
|
254
|
+
# Example
|
|
255
|
+
ng blame src/commands/blame.ts
|
|
256
|
+
ng blame packages/git/src/commands/blame.ts
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Features:**
|
|
260
|
+
- ✅ **Full Diff Display**: Shows complete diff for each commit (not just commit messages)
|
|
261
|
+
- ✅ **Interactive Navigation**: Browse through commits with keyboard shortcuts
|
|
262
|
+
- ✅ **Smart Caching**: Fetches git history once, then navigates instantly
|
|
263
|
+
- ✅ **Binary File Support**: Detects and handles binary files gracefully
|
|
264
|
+
- ✅ **Large Diff Protection**: Limits display to 50 lines to prevent terminal overflow
|
|
265
|
+
- ✅ **Follow File Renames**: Uses `--follow` to track history across renames
|
|
266
|
+
|
|
267
|
+
**Interactive Controls:**
|
|
268
|
+
|
|
269
|
+
| Key | Action | Description |
|
|
270
|
+
|-----|--------|-------------|
|
|
271
|
+
| `n` | Next commit | Move forward in time (to newer commits) |
|
|
272
|
+
| `p` | Previous commit | Move backward in time (to older commits) |
|
|
273
|
+
| `j` | Jump | Jump to a specific commit by number |
|
|
274
|
+
| `q` | Quit | Exit the navigator |
|
|
275
|
+
|
|
276
|
+
**Display Information:**
|
|
277
|
+
|
|
278
|
+
Each commit shows:
|
|
279
|
+
- 📝 Commit number (e.g., `Commit 3/10`)
|
|
280
|
+
- 🔖 Short commit hash (8 characters, colored)
|
|
281
|
+
- 👤 Author name (colored)
|
|
282
|
+
- 📅 Commit date (dimmed)
|
|
283
|
+
- 💬 Commit message
|
|
284
|
+
- 📄 Full diff with git standard formatting (red for deletions, green for additions)
|
|
285
|
+
|
|
286
|
+
**Special Handling:**
|
|
287
|
+
|
|
288
|
+
- **Binary Files**: Shows "📄 Binary file - diff not available" instead of binary content
|
|
289
|
+
- **Large Diffs**: Displays first 50 lines with truncation notice
|
|
290
|
+
```
|
|
291
|
+
(Showing first 50 lines of 123)
|
|
292
|
+
... (truncated)
|
|
293
|
+
```
|
|
294
|
+
- **Empty History**: Warns if file has no git history
|
|
295
|
+
- **Missing Files**: Clear error if file doesn't exist
|
|
296
|
+
|
|
297
|
+
**Example Output:**
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
Found 10 commits for src/commands/blame.ts
|
|
301
|
+
Use [n/p] to navigate, [j] to jump, [q] to quit
|
|
302
|
+
|
|
303
|
+
📝 Commit 1/10
|
|
304
|
+
abc123de - John Doe - Mon Feb 2 12:00:00 2026
|
|
305
|
+
feat(git): add interactive commit navigator
|
|
306
|
+
|
|
307
|
+
--- Diff ---
|
|
308
|
+
diff --git a/src/commands/blame.ts b/src/commands/blame.ts
|
|
309
|
+
new file mode 100644
|
|
310
|
+
index 0000000..1234567
|
|
311
|
+
--- /dev/null
|
|
312
|
+
+++ b/src/commands/blame.ts
|
|
313
|
+
@@ -0,0 +1,315 @@
|
|
314
|
+
+import path from 'node:path'
|
|
315
|
+
+import readline from 'node:readline'
|
|
316
|
+
...
|
|
317
|
+
|
|
318
|
+
--- Actions ---
|
|
319
|
+
[n] Next commit [p] Previous commit [j] Jump [q] Quit
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Use Cases:**
|
|
323
|
+
|
|
324
|
+
- 📖 **Code Review**: Understand how a file evolved over time
|
|
325
|
+
- 🐛 **Bug Investigation**: Find when a specific line was changed
|
|
326
|
+
- 📚 **Learning**: Study the development history of a feature
|
|
327
|
+
- 🔍 **Audit**: Review all changes made to a critical file
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
### Git History Viewer (`ng hist` / `ng history`)
|
|
332
|
+
|
|
333
|
+
Display git history with an interactive, scrollable graph view.
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
# Show full git history
|
|
337
|
+
ng hist
|
|
338
|
+
|
|
339
|
+
# Limit number of commits
|
|
340
|
+
ng hist -n 20
|
|
341
|
+
ng hist --number 50
|
|
342
|
+
|
|
343
|
+
# Using alias
|
|
344
|
+
ng history
|
|
345
|
+
ng history -n 10
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**Features:**
|
|
349
|
+
- ✅ **Beautiful Graph Format**: Visualizes branch structure with commit tree
|
|
350
|
+
- ✅ **Interactive Navigation**: Scroll through history with keyboard or mouse
|
|
351
|
+
- ✅ **Optimized Display**: Automatically adjusts to terminal size
|
|
352
|
+
- ✅ **Status Bar**: Shows current position and available shortcuts
|
|
353
|
+
- ✅ **Color-Coded Output**:
|
|
354
|
+
- Cyan: Commit hash
|
|
355
|
+
- Green: Commit date
|
|
356
|
+
- Magenta: Author name
|
|
357
|
+
- Yellow: Branch references
|
|
358
|
+
|
|
359
|
+
**Interactive Controls:**
|
|
360
|
+
|
|
361
|
+
| Key | Action | Description |
|
|
362
|
+
|-----|--------|-------------|
|
|
363
|
+
| `↑` / `k` | Scroll up | Move up through commits |
|
|
364
|
+
| `↓` / `j` | Scroll down | Move down through commits |
|
|
365
|
+
| `gg` | Jump to top | Go to the oldest commit |
|
|
366
|
+
| `G` | Jump to bottom | Go to the newest commit (Shift+G) |
|
|
367
|
+
| `Page Up` | Page up | Scroll up one page |
|
|
368
|
+
| `Page Down` | Page down | Scroll down one page |
|
|
369
|
+
| `q` / `Enter` | Quit | Exit the viewer |
|
|
370
|
+
|
|
371
|
+
**Display Information:**
|
|
372
|
+
|
|
373
|
+
Each commit shows:
|
|
374
|
+
- 🔖 Short commit hash (cyan, bold)
|
|
375
|
+
- 📅 Commit date and time (green)
|
|
376
|
+
- 👤 Author name (magenta)
|
|
377
|
+
- 🌿 Branch and tag references (yellow)
|
|
378
|
+
- 💬 Commit message
|
|
379
|
+
|
|
380
|
+
**Status Bar:**
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
↑↓/jk: Scroll | gg/G: Top/Bottom | PgUp/PgDn | q: Quit | Lines 1-42/150
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**Layout Optimization:**
|
|
387
|
+
|
|
388
|
+
- Automatically calculates optimal view height based on terminal size
|
|
389
|
+
- Reserves space for UI elements (borders, status bar)
|
|
390
|
+
- Ensures minimum of 10 lines for content display
|
|
391
|
+
- Removes unnecessary margins for maximum content visibility
|
|
392
|
+
|
|
393
|
+
**Use Cases:**
|
|
394
|
+
|
|
395
|
+
- 📊 **Project Overview**: Quickly see commit history and branch structure
|
|
396
|
+
- 🔍 **Context Browsing**: Understand recent changes before switching branches
|
|
397
|
+
- 📝 **Review History**: Check recent commits before pulling or pushing
|
|
398
|
+
- 🎯 **Navigation**: Find specific commits in the history
|
|
399
|
+
|
|
400
|
+
**Example Output:**
|
|
401
|
+
|
|
402
|
+
```
|
|
403
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
404
|
+
│* abc123de 2026-02-06 14:54:23 [GaoZimeng] (HEAD -> main) │
|
|
405
|
+
││ refactor(git): main increase hist viewer height line │
|
|
406
|
+
│* 1a40997 2026-02-06 14:52:15 [GaoZimeng] │
|
|
407
|
+
││ feat(git): fetch remote branches before pull │
|
|
408
|
+
│* a3be508 2026-02-06 14:51:23 [GaoZimeng] │
|
|
409
|
+
││ refactor(git): change branch selection from search to select│
|
|
410
|
+
│* 172403f 2026-02-06 14:50:12 [GaoZimeng] │
|
|
411
|
+
││ feat(git): enhance merge command with commit customization │
|
|
412
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
413
|
+
│ ↑↓/jk: Scroll | gg/G: Top/Bottom | PgUp/PgDn | q: Quit | Lines │
|
|
414
|
+
│ 1-10/150 │
|
|
415
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
242
420
|
### Stash Operations (`ng stash` / `ng st`)
|
|
243
421
|
|
|
244
422
|
Advanced stash management.
|
|
@@ -418,6 +596,93 @@ ng branch clean
|
|
|
418
596
|
# Confirm deletion
|
|
419
597
|
```
|
|
420
598
|
|
|
599
|
+
### Investigating File History
|
|
600
|
+
|
|
601
|
+
```bash
|
|
602
|
+
# Understand how a file evolved over time
|
|
603
|
+
ng blame src/utils/date.ts
|
|
604
|
+
|
|
605
|
+
# Interactive navigation:
|
|
606
|
+
# - Press 'n' to see next commit
|
|
607
|
+
# - Press 'p' to go back to previous commit
|
|
608
|
+
# - Press 'j' to jump to commit 5/10
|
|
609
|
+
# - Press 'q' when done reviewing
|
|
610
|
+
|
|
611
|
+
# Each commit shows:
|
|
612
|
+
# - Full commit hash, author, date, message
|
|
613
|
+
# - Complete diff (what changed)
|
|
614
|
+
# - Current position (e.g., "Commit 3/10")
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
**Real-world scenarios:**
|
|
618
|
+
|
|
619
|
+
- 🐛 **Bug Investigation**: Find when a bug was introduced
|
|
620
|
+
```bash
|
|
621
|
+
ng blame src/auth/login.ts
|
|
622
|
+
# Press 'n' repeatedly to review changes chronologically
|
|
623
|
+
# Look for the commit that broke the functionality
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
- 📖 **Code Review**: Understand the evolution of a complex function
|
|
627
|
+
```bash
|
|
628
|
+
ng blame src/api/handlers.ts
|
|
629
|
+
# Navigate through commits to see how the logic developed
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
- 🔍 **Audit Trail**: Review all changes to a security-critical file
|
|
633
|
+
```bash
|
|
634
|
+
ng blame src/config/security.ts
|
|
635
|
+
# Use 'j' to jump to specific commits of interest
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
### Browsing Project History
|
|
641
|
+
|
|
642
|
+
```bash
|
|
643
|
+
# View full git history with beautiful graph
|
|
644
|
+
ng hist
|
|
645
|
+
|
|
646
|
+
# View last 20 commits
|
|
647
|
+
ng hist -n 20
|
|
648
|
+
|
|
649
|
+
# Interactive navigation:
|
|
650
|
+
# - Use ↑/↓ or j/k to scroll through commits
|
|
651
|
+
# - Press 'gg' to jump to oldest commit
|
|
652
|
+
# - Press 'G' (Shift+G) to jump to newest commit
|
|
653
|
+
# - Use Page Up/Down to scroll by pages
|
|
654
|
+
# - Press 'q' or Enter to exit
|
|
655
|
+
|
|
656
|
+
# Features:
|
|
657
|
+
# - Color-coded output (hash, date, author, branches)
|
|
658
|
+
# - Visual commit graph showing branch structure
|
|
659
|
+
# - Status bar showing current position
|
|
660
|
+
# - Automatically adjusts to terminal size
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
**Real-world scenarios:**
|
|
664
|
+
|
|
665
|
+
- 📊 **Before Pulling**: Check what's been committed recently
|
|
666
|
+
```bash
|
|
667
|
+
ng hist -n 10
|
|
668
|
+
# Review recent commits before doing `ng pull`
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
- 🎯 **Finding Commits**: Locate a specific commit in history
|
|
672
|
+
```bash
|
|
673
|
+
ng hist
|
|
674
|
+
# Press 'gg' to go to oldest commit
|
|
675
|
+
# Use ↓/j to scroll forward to find what you need
|
|
676
|
+
# Note the commit hash (e.g., abc123de)
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
- 🌿 **Branch Overview**: Understand branch structure and merges
|
|
680
|
+
```bash
|
|
681
|
+
ng hist -n 50
|
|
682
|
+
# See how branches diverged and merged
|
|
683
|
+
# Identify branch points and merge commits
|
|
684
|
+
```
|
|
685
|
+
|
|
421
686
|
---
|
|
422
687
|
|
|
423
688
|
## Comparison: Git vs `ng`
|
|
@@ -432,6 +697,18 @@ ng branch clean
|
|
|
432
697
|
| List branches | `git branch` | `ng list` (enhanced display) |
|
|
433
698
|
| Merge | `git merge` | `ng merge` (auto stash + searchable) |
|
|
434
699
|
| Stash | `git stash` | `ng stash` (enhanced management) |
|
|
700
|
+
| Blame | `git blame` (line-by-line) | `ng blame` (full commit history with diff) |
|
|
701
|
+
| Log/History | `git log` (static output) | `ng hist` (interactive graph viewer) |
|
|
702
|
+
|
|
703
|
+
**Key Difference - `ng blame` vs `git blame`:**
|
|
704
|
+
|
|
705
|
+
| Feature | `git blame` | `ng blame` |
|
|
706
|
+
|---------|-------------|------------|
|
|
707
|
+
| Shows | Line-by-line annotations | Full commit history with diffs |
|
|
708
|
+
| Navigation | Scroll through file | Interactive commit navigation (n/p/j/q) |
|
|
709
|
+
| Diff View | No (use separately) | Yes, included for each commit |
|
|
710
|
+
| File Renames | Limited | Full support with `--follow` |
|
|
711
|
+
| Best For | Finding who changed a line | Understanding file evolution |
|
|
435
712
|
|
|
436
713
|
---
|
|
437
714
|
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addFiles, colors, createCheckbox, createCommand, createConfirm, createHelpExample, createInput, createNote, createOptions,
|
|
1
|
+
import { addFiles, colors, createCheckbox, createCommand, createConfirm, createHelpExample, createInput, createNote, createOptions, createSelect, createSpinner, exit, getCurrentBranch, getGitStatus, intro, isEmpty, isString, loadConfig, log, outro, readPackage, safeAwait, x, xASync } from "@nemo-cli/shared";
|
|
2
2
|
import { BigText, ErrorMessage, Message, renderHistViewer, renderStashList, renderStatusViewer } from "@nemo-cli/ui";
|
|
3
3
|
import path, { dirname, join } from "node:path";
|
|
4
4
|
import readline from "node:readline";
|
|
@@ -376,7 +376,7 @@ const getLocalBranches = async () => {
|
|
|
376
376
|
currentBranch: formatBranch$1(currentBranch)
|
|
377
377
|
};
|
|
378
378
|
};
|
|
379
|
-
const
|
|
379
|
+
const getRemoteBranchOptions = async () => {
|
|
380
380
|
const { branches } = await getRemoteBranches();
|
|
381
381
|
const currentBranch = await getCurrentBranch();
|
|
382
382
|
return {
|
|
@@ -388,7 +388,7 @@ const getRemoteOptions = async () => {
|
|
|
388
388
|
currentBranch
|
|
389
389
|
};
|
|
390
390
|
};
|
|
391
|
-
const
|
|
391
|
+
const getLocalBranchOptions = async () => {
|
|
392
392
|
const { branches, currentBranch } = await getLocalBranches();
|
|
393
393
|
return {
|
|
394
394
|
options: branches.map((branch) => ({
|
|
@@ -399,7 +399,7 @@ const getLocalOptions = async () => {
|
|
|
399
399
|
currentBranch
|
|
400
400
|
};
|
|
401
401
|
};
|
|
402
|
-
const
|
|
402
|
+
const getRemoteRepositoryOptions = async () => {
|
|
403
403
|
const { remotes } = await getRemotes();
|
|
404
404
|
const validRemotes = remotes.filter((remote) => remote.trim().length > 0);
|
|
405
405
|
const uniqueRemotes = Array.from(new Set(validRemotes));
|
|
@@ -494,18 +494,18 @@ const handleMergeCommit = async () => {
|
|
|
494
494
|
}
|
|
495
495
|
};
|
|
496
496
|
const handleGitPull = async (branch, options = {}) => {
|
|
497
|
-
const { rebase = false } = options;
|
|
497
|
+
const { rebase = false, remote = "origin" } = options;
|
|
498
498
|
const modeText = rebase ? "rebase" : "merge";
|
|
499
499
|
log.show(`Pulling from remote (${modeText} mode)...`, { type: "step" });
|
|
500
500
|
try {
|
|
501
501
|
const [error, result] = await xASync("git", rebase ? [
|
|
502
502
|
"pull",
|
|
503
503
|
"--rebase",
|
|
504
|
-
|
|
504
|
+
remote,
|
|
505
505
|
branch
|
|
506
506
|
] : [
|
|
507
507
|
"pull",
|
|
508
|
-
|
|
508
|
+
remote,
|
|
509
509
|
branch
|
|
510
510
|
], { nodeOptions: { stdio: "inherit" } });
|
|
511
511
|
if (error) {
|
|
@@ -881,13 +881,13 @@ function checkoutCommand(command) {
|
|
|
881
881
|
initialValue: true
|
|
882
882
|
});
|
|
883
883
|
if (isLocal) {
|
|
884
|
-
const { options } = await
|
|
884
|
+
const { options } = await getLocalBranchOptions();
|
|
885
885
|
handleCheckout(await createSelect({
|
|
886
886
|
message: `Select the ${colors.bgGreen(" local ")} branch to checkout`,
|
|
887
887
|
options
|
|
888
888
|
}));
|
|
889
889
|
} else {
|
|
890
|
-
const { options } = await
|
|
890
|
+
const { options } = await getRemoteBranchOptions();
|
|
891
891
|
const selectedBranch = await createSelect({
|
|
892
892
|
message: `Select the ${colors.bgYellow(" remote ")} branch to checkout`,
|
|
893
893
|
options
|
|
@@ -1089,50 +1089,50 @@ const pushInteractive = async () => {
|
|
|
1089
1089
|
log.error("No branch selected. Aborting push operation.");
|
|
1090
1090
|
return;
|
|
1091
1091
|
}
|
|
1092
|
-
let
|
|
1092
|
+
let repositories;
|
|
1093
1093
|
try {
|
|
1094
|
-
|
|
1094
|
+
repositories = (await getRemoteRepositoryOptions()).remotes;
|
|
1095
1095
|
} catch (error) {
|
|
1096
1096
|
log.error(`Failed to get remote repositories: ${error instanceof Error ? error.message : String(error)}`);
|
|
1097
1097
|
log.show("Hint: Make sure you're in a git repository and have configured remotes.", { type: "info" });
|
|
1098
1098
|
return;
|
|
1099
1099
|
}
|
|
1100
|
-
if (
|
|
1100
|
+
if (repositories.length === 0) {
|
|
1101
1101
|
log.error("No remote repositories found. Aborting push operation.");
|
|
1102
1102
|
log.show("Hint: Run `git remote add <name> <url>` to add a remote repository.", { type: "info" });
|
|
1103
1103
|
return;
|
|
1104
1104
|
}
|
|
1105
|
-
let
|
|
1106
|
-
if (
|
|
1105
|
+
let selectedRepository = repositories[0];
|
|
1106
|
+
if (repositories.length > 1) selectedRepository = await createSelect({
|
|
1107
1107
|
message: "Select remote repository",
|
|
1108
|
-
options:
|
|
1109
|
-
label:
|
|
1110
|
-
value:
|
|
1108
|
+
options: repositories.map((repo) => ({
|
|
1109
|
+
label: repo,
|
|
1110
|
+
value: repo
|
|
1111
1111
|
})),
|
|
1112
|
-
initialValue:
|
|
1112
|
+
initialValue: repositories[0]
|
|
1113
1113
|
});
|
|
1114
|
-
if (await createConfirm({ message: `Do you want to push ${colors.bgGreen(currentBranch)} to ${
|
|
1115
|
-
await handlePush(currentBranch,
|
|
1114
|
+
if (await createConfirm({ message: `Do you want to push ${colors.bgGreen(currentBranch)} to ${selectedRepository}?` })) {
|
|
1115
|
+
await handlePush(currentBranch, selectedRepository);
|
|
1116
1116
|
return;
|
|
1117
1117
|
}
|
|
1118
|
-
const { options } = await
|
|
1118
|
+
const { options } = await getRemoteBranchOptions();
|
|
1119
1119
|
const selectedBranch = await createSelect({
|
|
1120
1120
|
message: "Select the branch to push",
|
|
1121
1121
|
options,
|
|
1122
1122
|
initialValue: "main"
|
|
1123
1123
|
});
|
|
1124
|
-
|
|
1125
|
-
if (
|
|
1126
|
-
if (!await createConfirm({ message: `Push ${colors.bgGreen(selectedBranch)} to ${
|
|
1124
|
+
selectedRepository = repositories[0];
|
|
1125
|
+
if (repositories.length > 1) {
|
|
1126
|
+
if (!await createConfirm({ message: `Push ${colors.bgGreen(selectedBranch)} to ${selectedRepository}?` })) selectedRepository = await createSelect({
|
|
1127
1127
|
message: "Select remote repository",
|
|
1128
|
-
options:
|
|
1129
|
-
label:
|
|
1130
|
-
value:
|
|
1128
|
+
options: repositories.map((repo) => ({
|
|
1129
|
+
label: repo,
|
|
1130
|
+
value: repo
|
|
1131
1131
|
})),
|
|
1132
|
-
initialValue:
|
|
1132
|
+
initialValue: selectedRepository
|
|
1133
1133
|
});
|
|
1134
1134
|
}
|
|
1135
|
-
await handlePush(selectedBranch,
|
|
1135
|
+
await handlePush(selectedBranch, selectedRepository);
|
|
1136
1136
|
};
|
|
1137
1137
|
|
|
1138
1138
|
//#endregion
|
|
@@ -1807,24 +1807,43 @@ function listCommand(command) {
|
|
|
1807
1807
|
//#region src/commands/merge.ts
|
|
1808
1808
|
const handleMerge = async (branch) => {
|
|
1809
1809
|
const spinner = createSpinner(`Merging branch ${branch}...`);
|
|
1810
|
-
const args = [
|
|
1810
|
+
const args = [
|
|
1811
|
+
"merge",
|
|
1812
|
+
"--no-edit",
|
|
1813
|
+
branch
|
|
1814
|
+
];
|
|
1811
1815
|
const stashResult = await handleGitStash(void 0, {
|
|
1812
1816
|
branch,
|
|
1813
1817
|
operation: "merge"
|
|
1814
1818
|
});
|
|
1819
|
+
if (!stashResult) {
|
|
1820
|
+
spinner.stop("Cannot proceed with merge: failed to stash changes.");
|
|
1821
|
+
return;
|
|
1822
|
+
}
|
|
1815
1823
|
try {
|
|
1816
|
-
const [error] = await xASync("git", args, { nodeOptions: { stdio: "inherit" } });
|
|
1817
|
-
if (error)
|
|
1818
|
-
|
|
1824
|
+
const [error, result] = await xASync("git", args, { nodeOptions: { stdio: "inherit" } });
|
|
1825
|
+
if (error) {
|
|
1826
|
+
spinner.stop();
|
|
1827
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1828
|
+
throw new Error(`Failed to merge branch ${branch}: ${errorMessage}`);
|
|
1829
|
+
}
|
|
1830
|
+
spinner.stop();
|
|
1831
|
+
if (result.stdout.includes("Merge branch") || result.stdout.includes("Merge made by")) await handleMergeCommit();
|
|
1832
|
+
log.show(colors.green(`Successfully merged branch ${colors.bgGreen(branch)}.`), { type: "success" });
|
|
1833
|
+
} catch (error) {
|
|
1834
|
+
spinner.stop();
|
|
1835
|
+
log.show(`Failed to merge branch ${branch}.`, { type: "error" });
|
|
1836
|
+
log.error(error);
|
|
1837
|
+
throw error;
|
|
1819
1838
|
} finally {
|
|
1820
|
-
stashResult
|
|
1839
|
+
if (stashResult) await handleGitPop(stashResult);
|
|
1821
1840
|
}
|
|
1822
1841
|
};
|
|
1823
1842
|
function mergeCommand(command) {
|
|
1824
1843
|
command.command("merge").alias("mg").argument("[branch]", "The branch to merge").option("-l, --local", "Merge a local branch").option("-r, --remote", "Merge a remote branch").option("-b, --branch <branch>", "Create and merge a new branch").description("Merge a branch").action(async (branch, params) => {
|
|
1825
1844
|
let isLocal = params.local;
|
|
1826
1845
|
if (branch) {
|
|
1827
|
-
handleMerge(branch);
|
|
1846
|
+
await handleMerge(branch);
|
|
1828
1847
|
return;
|
|
1829
1848
|
}
|
|
1830
1849
|
if (isEmpty(params)) isLocal = await createSelect({
|
|
@@ -1839,18 +1858,20 @@ function mergeCommand(command) {
|
|
|
1839
1858
|
initialValue: false
|
|
1840
1859
|
});
|
|
1841
1860
|
if (isLocal) {
|
|
1842
|
-
const { options } = await
|
|
1843
|
-
handleMerge(await
|
|
1861
|
+
const { options, currentBranch } = await getLocalBranchOptions();
|
|
1862
|
+
await handleMerge(await createSelect({
|
|
1844
1863
|
message: "Select the branch to merge",
|
|
1845
|
-
options
|
|
1864
|
+
options,
|
|
1865
|
+
initialValue: currentBranch
|
|
1846
1866
|
}));
|
|
1847
1867
|
} else {
|
|
1848
|
-
const { options } = await
|
|
1849
|
-
const selectedBranch = await
|
|
1868
|
+
const { options, currentBranch } = await getRemoteBranchOptions();
|
|
1869
|
+
const selectedBranch = await createSelect({
|
|
1850
1870
|
message: "Select the branch to merge",
|
|
1851
|
-
options
|
|
1871
|
+
options,
|
|
1872
|
+
initialValue: currentBranch
|
|
1852
1873
|
});
|
|
1853
|
-
if (await createConfirm({ message: `Do you want to merge ${colors.bgRed(selectedBranch)}?` })) handleMerge(selectedBranch);
|
|
1874
|
+
if (await createConfirm({ message: `Do you want to merge ${colors.bgRed(selectedBranch)}?` })) await handleMerge(selectedBranch);
|
|
1854
1875
|
}
|
|
1855
1876
|
});
|
|
1856
1877
|
}
|
|
@@ -1859,7 +1880,40 @@ function mergeCommand(command) {
|
|
|
1859
1880
|
//#region src/commands/pull.ts
|
|
1860
1881
|
function pullCommand(command) {
|
|
1861
1882
|
command.command("pull").alias("pl").description("Pull git branch").option("-r, --rebase", "Use rebase mode instead of merge").option("-m, --merge", "Use merge mode (default)").action(async (options) => {
|
|
1862
|
-
const
|
|
1883
|
+
const [error, result] = await safeAwait(getRemoteRepositoryOptions());
|
|
1884
|
+
if (error) {
|
|
1885
|
+
log.error(`Failed to get remote repositories: ${error.message}`);
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
const repositories = result.remotes;
|
|
1889
|
+
if (repositories.length === 0) {
|
|
1890
|
+
log.error("No remote repositories found. Aborting pull operation.");
|
|
1891
|
+
log.show("Hint: Use \"git remote add <name> <url>\" to add a remote repository.", { type: "info" });
|
|
1892
|
+
return;
|
|
1893
|
+
}
|
|
1894
|
+
const selectedRepository = repositories.length > 1 ? (await safeAwait(createSelect({
|
|
1895
|
+
message: "Select remote repository",
|
|
1896
|
+
options: result.options,
|
|
1897
|
+
initialValue: repositories[0]
|
|
1898
|
+
})))[1] : repositories[0];
|
|
1899
|
+
if (!selectedRepository) {
|
|
1900
|
+
log.error("No remote selected. Aborting pull operation.");
|
|
1901
|
+
return;
|
|
1902
|
+
}
|
|
1903
|
+
const spinner = createSpinner("Fetching latest remote branches...");
|
|
1904
|
+
const [fetchError] = await xASync("git", [
|
|
1905
|
+
"fetch",
|
|
1906
|
+
selectedRepository,
|
|
1907
|
+
"--prune"
|
|
1908
|
+
], { timeout: 3e4 });
|
|
1909
|
+
if (fetchError) {
|
|
1910
|
+
spinner.stop("Failed to fetch latest remote branches");
|
|
1911
|
+
log.error(`Failed to fetch from ${selectedRepository}: ${fetchError.message}`);
|
|
1912
|
+
log.show("Please check your network connection and try again.", { type: "info" });
|
|
1913
|
+
return;
|
|
1914
|
+
}
|
|
1915
|
+
spinner.stop("Successfully fetched latest remote branches");
|
|
1916
|
+
const { options: branchOptions, currentBranch } = await getRemoteBranchOptions();
|
|
1863
1917
|
if (!branchOptions.length) {
|
|
1864
1918
|
log.error("No branches found. Please check your git repository.");
|
|
1865
1919
|
return;
|
|
@@ -1879,11 +1933,11 @@ function pullCommand(command) {
|
|
|
1879
1933
|
options: [{
|
|
1880
1934
|
label: "Merge (default)",
|
|
1881
1935
|
value: "merge",
|
|
1882
|
-
hint:
|
|
1936
|
+
hint: `git pull ${selectedRepository} ${selectedBranch}`
|
|
1883
1937
|
}, {
|
|
1884
1938
|
label: "Rebase",
|
|
1885
1939
|
value: "rebase",
|
|
1886
|
-
hint:
|
|
1940
|
+
hint: `git pull --rebase ${selectedRepository} ${selectedBranch}`
|
|
1887
1941
|
}],
|
|
1888
1942
|
initialValue: "merge"
|
|
1889
1943
|
}) === "rebase";
|
|
@@ -1891,7 +1945,10 @@ function pullCommand(command) {
|
|
|
1891
1945
|
branch: selectedBranch,
|
|
1892
1946
|
operation: "pull"
|
|
1893
1947
|
});
|
|
1894
|
-
await handleGitPull(selectedBranch, {
|
|
1948
|
+
await handleGitPull(selectedBranch, {
|
|
1949
|
+
remote: selectedRepository,
|
|
1950
|
+
rebase: useRebase
|
|
1951
|
+
});
|
|
1895
1952
|
stashResult && handleGitPop(stashResult);
|
|
1896
1953
|
});
|
|
1897
1954
|
}
|