@gw-tools/gw 0.12.23 → 0.12.26
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 +136 -135
- package/bin/gw +0 -0
- package/install.js +34 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,6 +7,10 @@ A command-line tool for managing git worktrees, built with Deno.
|
|
|
7
7
|
- [gw - Git Worktree Tools](#gw---git-worktree-tools)
|
|
8
8
|
- [Table of Contents](#table-of-contents)
|
|
9
9
|
- [Quick Start](#quick-start)
|
|
10
|
+
- [Initial Setup: Secrets in the Default Branch](#initial-setup-secrets-in-the-default-branch)
|
|
11
|
+
- [First-Time Setup Flow](#first-time-setup-flow)
|
|
12
|
+
- [Why This Matters](#why-this-matters)
|
|
13
|
+
- [Keeping Secrets Updated](#keeping-secrets-updated)
|
|
10
14
|
- [Features](#features)
|
|
11
15
|
- [Installation](#installation)
|
|
12
16
|
- [Via npm (Recommended)](#via-npm-recommended)
|
|
@@ -21,6 +25,7 @@ A command-line tool for managing git worktrees, built with Deno.
|
|
|
21
25
|
- [Options](#options)
|
|
22
26
|
- [Examples](#examples)
|
|
23
27
|
- [Auto-Copy Configuration](#auto-copy-configuration)
|
|
28
|
+
- [Hooks](#hooks)
|
|
24
29
|
- [cd](#cd)
|
|
25
30
|
- [Arguments](#arguments-1)
|
|
26
31
|
- [Examples](#examples-1)
|
|
@@ -38,18 +43,21 @@ A command-line tool for managing git worktrees, built with Deno.
|
|
|
38
43
|
- [init](#init)
|
|
39
44
|
- [Options](#options-3)
|
|
40
45
|
- [Examples](#examples-5)
|
|
46
|
+
- [Hook Variables](#hook-variables)
|
|
47
|
+
- [Auto-Cleanup Configuration](#auto-cleanup-configuration)
|
|
41
48
|
- [When to Use](#when-to-use)
|
|
42
49
|
- [show-init](#show-init)
|
|
43
|
-
- [Options](#options-
|
|
44
|
-
- [Examples](#examples-
|
|
50
|
+
- [Options](#options-4)
|
|
51
|
+
- [Examples](#examples-6)
|
|
52
|
+
- [Output Example](#output-example)
|
|
45
53
|
- [When to Use](#when-to-use-1)
|
|
46
54
|
- [sync](#sync)
|
|
47
55
|
- [Arguments](#arguments-2)
|
|
48
|
-
- [Options](#options-4)
|
|
49
|
-
- [Examples](#examples-6)
|
|
50
|
-
- [clean](#clean)
|
|
51
56
|
- [Options](#options-5)
|
|
52
57
|
- [Examples](#examples-7)
|
|
58
|
+
- [clean](#clean)
|
|
59
|
+
- [Options](#options-6)
|
|
60
|
+
- [Examples](#examples-8)
|
|
53
61
|
- [How It Works](#how-it-works-3)
|
|
54
62
|
- [Git Worktree Proxy Commands](#git-worktree-proxy-commands)
|
|
55
63
|
- [list (ls)](#list-ls)
|
|
@@ -63,11 +71,7 @@ A command-line tool for managing git worktrees, built with Deno.
|
|
|
63
71
|
- [Typical Workflow](#typical-workflow)
|
|
64
72
|
- [Development](#development)
|
|
65
73
|
- [Local Development \& Testing](#local-development--testing)
|
|
66
|
-
- [
|
|
67
|
-
- [Method 2: Symlink to Compiled Binary (Faster Execution)](#method-2-symlink-to-compiled-binary-faster-execution)
|
|
68
|
-
- [Method 3: Development Wrapper Script (Best of Both Worlds)](#method-3-development-wrapper-script-best-of-both-worlds)
|
|
69
|
-
- [Method 4: npm link (For Testing Installation)](#method-4-npm-link-for-testing-installation)
|
|
70
|
-
- [Watch Mode for Active Development](#watch-mode-for-active-development)
|
|
74
|
+
- [Shell Alias Method (Recommended)](#shell-alias-method-recommended)
|
|
71
75
|
- [Available Scripts](#available-scripts)
|
|
72
76
|
- [Publishing](#publishing)
|
|
73
77
|
- [Automated Release (Recommended)](#automated-release-recommended)
|
|
@@ -76,6 +80,8 @@ A command-line tool for managing git worktrees, built with Deno.
|
|
|
76
80
|
- [Version Management](#version-management)
|
|
77
81
|
- [Project Structure](#project-structure)
|
|
78
82
|
- [Adding New Commands](#adding-new-commands)
|
|
83
|
+
- [Custom Commands (like `add`, `copy`)](#custom-commands-like-add-copy)
|
|
84
|
+
- [Git Proxy Commands (like `list`, `remove`)](#git-proxy-commands-like-list-remove)
|
|
79
85
|
- [License](#license)
|
|
80
86
|
|
|
81
87
|
## Quick Start
|
|
@@ -220,11 +226,7 @@ gw init --root /path/to/your/repo.git
|
|
|
220
226
|
{
|
|
221
227
|
"root": "/Users/username/Workspace/my-project.git",
|
|
222
228
|
"defaultBranch": "main",
|
|
223
|
-
"autoCopyFiles": [
|
|
224
|
-
".env",
|
|
225
|
-
"components/agents/.env",
|
|
226
|
-
"components/ui/.vercel/"
|
|
227
|
-
],
|
|
229
|
+
"autoCopyFiles": [".env", "components/agents/.env", "components/ui/.vercel/"],
|
|
228
230
|
"hooks": {
|
|
229
231
|
"add": {
|
|
230
232
|
"pre": ["echo 'Creating worktree: {worktree}'"],
|
|
@@ -283,6 +285,7 @@ If you try to add a worktree that already exists, the command will prompt you to
|
|
|
283
285
|
#### Options
|
|
284
286
|
|
|
285
287
|
All `git worktree add` options are supported:
|
|
288
|
+
|
|
286
289
|
- `-b <branch>`: Create a new branch
|
|
287
290
|
- `-B <branch>`: Create or reset a branch
|
|
288
291
|
- `--detach`: Detach HEAD in new worktree
|
|
@@ -323,6 +326,7 @@ gw init --auto-copy-files .env,secrets/,components/ui/.vercel/
|
|
|
323
326
|
```
|
|
324
327
|
|
|
325
328
|
This creates:
|
|
329
|
+
|
|
326
330
|
```json
|
|
327
331
|
{
|
|
328
332
|
"root": "/path/to/repo.git",
|
|
@@ -336,6 +340,7 @@ Now every time you run `gw add`, these files will be automatically copied from y
|
|
|
336
340
|
#### Hooks
|
|
337
341
|
|
|
338
342
|
You can configure pre-add and post-add hooks to run commands before and after worktree creation. This is useful for:
|
|
343
|
+
|
|
339
344
|
- **Pre-add hooks**: Running validation scripts, checking prerequisites
|
|
340
345
|
- **Post-add hooks**: Installing dependencies, setting up the environment
|
|
341
346
|
|
|
@@ -350,12 +355,14 @@ gw init --pre-add "echo 'Creating: {worktree}'" --post-add "pnpm install" --post
|
|
|
350
355
|
**Hook Variables:**
|
|
351
356
|
|
|
352
357
|
Hooks support variable substitution:
|
|
358
|
+
|
|
353
359
|
- `{worktree}` - The worktree name (e.g., "feat/new-feature")
|
|
354
360
|
- `{worktreePath}` - Full absolute path to the worktree
|
|
355
361
|
- `{gitRoot}` - The git repository root path
|
|
356
362
|
- `{branch}` - The branch name
|
|
357
363
|
|
|
358
364
|
**Hook Behavior:**
|
|
365
|
+
|
|
359
366
|
- **Pre-add hooks** run before the worktree is created (in the git root directory). If any pre-add hook fails, the worktree creation is aborted.
|
|
360
367
|
- **Post-add hooks** run after the worktree is created and files are copied (in the new worktree directory). If a post-add hook fails, a warning is shown but the worktree creation is considered successful.
|
|
361
368
|
|
|
@@ -454,6 +461,7 @@ gw pull --remote upstream
|
|
|
454
461
|
3. Creates merge commit if histories have diverged
|
|
455
462
|
|
|
456
463
|
**Safety checks:**
|
|
464
|
+
|
|
457
465
|
- Blocks if you have uncommitted changes (use `--force` to override)
|
|
458
466
|
- Blocks if you're in a detached HEAD state
|
|
459
467
|
- Handles merge conflicts gracefully with clear guidance
|
|
@@ -463,6 +471,7 @@ gw pull --remote upstream
|
|
|
463
471
|
**Configuration:**
|
|
464
472
|
|
|
465
473
|
The default branch is read from `.gw/config.json`:
|
|
474
|
+
|
|
466
475
|
```json
|
|
467
476
|
{
|
|
468
477
|
"defaultBranch": "main"
|
|
@@ -473,7 +482,16 @@ If not configured, defaults to "main".
|
|
|
473
482
|
|
|
474
483
|
### install-shell
|
|
475
484
|
|
|
476
|
-
Install or remove shell integration for the `gw cd` command. This is automatically run during `npm install`, but can be run manually if needed.
|
|
485
|
+
Install or remove shell integration for the `gw cd` command and enable real-time streaming output. This is automatically run during `npm install`, but can be run manually if needed.
|
|
486
|
+
|
|
487
|
+
The installation creates an integration script in `~/.gw/shell/` and adds a single line to your shell configuration to source it, keeping your shell config clean and minimal.
|
|
488
|
+
|
|
489
|
+
Shell integration provides:
|
|
490
|
+
|
|
491
|
+
- **Navigation support**: `gw cd <worktree>` navigates directly to worktrees
|
|
492
|
+
- **Real-time streaming**: Command output streams as it's generated (no buffering)
|
|
493
|
+
- **Auto-navigation**: Automatically navigate after `gw add` and `gw remove` operations
|
|
494
|
+
- **Multi-alias support**: Install for different command names (e.g., `gw-dev` for development)
|
|
477
495
|
|
|
478
496
|
```bash
|
|
479
497
|
gw install-shell [options]
|
|
@@ -481,6 +499,8 @@ gw install-shell [options]
|
|
|
481
499
|
|
|
482
500
|
#### Options
|
|
483
501
|
|
|
502
|
+
- `--name, -n NAME`: Install under a different command name (default: `gw`)
|
|
503
|
+
- `--command, -c CMD`: Actual command to run (use with `--name` for aliases/dev)
|
|
484
504
|
- `--remove`: Remove shell integration
|
|
485
505
|
- `--quiet, -q`: Suppress output messages
|
|
486
506
|
- `-h, --help`: Show help message
|
|
@@ -491,19 +511,25 @@ gw install-shell [options]
|
|
|
491
511
|
# Install shell integration (usually not needed - auto-installed)
|
|
492
512
|
gw install-shell
|
|
493
513
|
|
|
494
|
-
#
|
|
495
|
-
gw
|
|
514
|
+
# Install for development (with Deno)
|
|
515
|
+
# Note: Remove any 'alias gw-dev=...' from .zshrc first!
|
|
516
|
+
gw install-shell --name gw-dev \
|
|
517
|
+
--command "deno run --allow-all ~/path/to/gw-tools/packages/gw-tool/src/main.ts"
|
|
518
|
+
|
|
519
|
+
# Remove shell integration for 'gw-dev'
|
|
520
|
+
gw install-shell --name gw-dev --remove
|
|
496
521
|
|
|
497
522
|
# Install quietly (for automation)
|
|
498
523
|
gw install-shell --quiet
|
|
499
524
|
```
|
|
500
525
|
|
|
501
526
|
**Supported Shells:**
|
|
502
|
-
- **Zsh** (~/.zshrc)
|
|
503
|
-
- **Bash** (~/.bashrc)
|
|
504
|
-
- **Fish** (~/.config/fish/functions/gw.fish)
|
|
505
527
|
|
|
506
|
-
|
|
528
|
+
- **Zsh** (~/.zshrc sources ~/.gw/shell/integration[-NAME].zsh)
|
|
529
|
+
- **Bash** (~/.bashrc sources ~/.gw/shell/integration[-NAME].bash)
|
|
530
|
+
- **Fish** (~/.config/fish/functions/[NAME].fish)
|
|
531
|
+
|
|
532
|
+
The command is idempotent - running it multiple times won't create duplicate entries. It will also automatically migrate old inline installations to the new format.
|
|
507
533
|
|
|
508
534
|
### root
|
|
509
535
|
|
|
@@ -604,6 +630,7 @@ gw init --help
|
|
|
604
630
|
#### Hook Variables
|
|
605
631
|
|
|
606
632
|
Hooks support variable substitution:
|
|
633
|
+
|
|
607
634
|
- `{worktree}` - The worktree name (e.g., "feat/new-feature")
|
|
608
635
|
- `{worktreePath}` - Full absolute path to the worktree
|
|
609
636
|
- `{gitRoot}` - The git repository root path
|
|
@@ -625,6 +652,7 @@ gw init --auto-clean --auto-copy-files .env --post-add "pnpm install"
|
|
|
625
652
|
```
|
|
626
653
|
|
|
627
654
|
**How it works:**
|
|
655
|
+
|
|
628
656
|
- Runs automatically on `gw add` and `gw list` commands (in the background, non-blocking)
|
|
629
657
|
- Only runs once per 24 hours (cooldown)
|
|
630
658
|
- **Never removes the `defaultBranch` worktree** - it's protected as the source for file syncing
|
|
@@ -640,6 +668,7 @@ This is an opt-in feature. Use `gw clean` for manual, interactive cleanup with m
|
|
|
640
668
|
#### When to Use
|
|
641
669
|
|
|
642
670
|
Use `gw init` to:
|
|
671
|
+
|
|
643
672
|
- Configure auto-copy files for automatic file copying on worktree creation
|
|
644
673
|
- Set up pre-add and post-add hooks for automation
|
|
645
674
|
- Configure the clean threshold for worktree age management
|
|
@@ -682,6 +711,7 @@ echo "## Setup\n\n\`\`\`bash\n$(gw show-init)\n\`\`\`" >> README.md
|
|
|
682
711
|
#### Output Example
|
|
683
712
|
|
|
684
713
|
If your `.gw/config.json` contains:
|
|
714
|
+
|
|
685
715
|
```json
|
|
686
716
|
{
|
|
687
717
|
"root": "/Users/username/Workspace/repo.git",
|
|
@@ -697,6 +727,7 @@ If your `.gw/config.json` contains:
|
|
|
697
727
|
```
|
|
698
728
|
|
|
699
729
|
Then `gw show-init` will output:
|
|
730
|
+
|
|
700
731
|
```bash
|
|
701
732
|
gw init --root /Users/username/Workspace/repo.git --auto-copy-files .env,secrets/ --post-add 'pnpm install'
|
|
702
733
|
```
|
|
@@ -704,6 +735,7 @@ gw init --root /Users/username/Workspace/repo.git --auto-copy-files .env,secrets
|
|
|
704
735
|
#### When to Use
|
|
705
736
|
|
|
706
737
|
Use `gw show-init` to:
|
|
738
|
+
|
|
707
739
|
- Document your setup in README files or team wikis
|
|
708
740
|
- Share configuration commands with team members
|
|
709
741
|
- Recreate the same configuration in another repository
|
|
@@ -788,6 +820,7 @@ gw init --clean-threshold 14
|
|
|
788
820
|
#### How It Works
|
|
789
821
|
|
|
790
822
|
The clean command:
|
|
823
|
+
|
|
791
824
|
1. Checks for worktrees older than the configured threshold (default: 7 days)
|
|
792
825
|
2. Verifies they have no uncommitted changes (unless `--force`)
|
|
793
826
|
3. Verifies they have no unpushed commits (unless `--force`)
|
|
@@ -795,6 +828,7 @@ The clean command:
|
|
|
795
828
|
5. Never removes bare/main repository worktrees
|
|
796
829
|
|
|
797
830
|
**Safety Features:**
|
|
831
|
+
|
|
798
832
|
- By default, only removes worktrees with NO uncommitted changes
|
|
799
833
|
- By default, only removes worktrees with NO unpushed commits
|
|
800
834
|
- Always prompts for confirmation before deletion
|
|
@@ -811,6 +845,7 @@ gw init --clean-threshold 14
|
|
|
811
845
|
```
|
|
812
846
|
|
|
813
847
|
This creates/updates the config:
|
|
848
|
+
|
|
814
849
|
```json
|
|
815
850
|
{
|
|
816
851
|
"root": "/path/to/repo.git",
|
|
@@ -834,6 +869,7 @@ gw ls
|
|
|
834
869
|
```
|
|
835
870
|
|
|
836
871
|
**Examples:**
|
|
872
|
+
|
|
837
873
|
```bash
|
|
838
874
|
gw list # List all worktrees
|
|
839
875
|
gw list --porcelain # Machine-readable output
|
|
@@ -851,6 +887,7 @@ gw rm <worktree>
|
|
|
851
887
|
```
|
|
852
888
|
|
|
853
889
|
**Examples:**
|
|
890
|
+
|
|
854
891
|
```bash
|
|
855
892
|
gw remove feat-branch # Remove a worktree
|
|
856
893
|
gw remove --force feat-branch # Force remove even if dirty
|
|
@@ -868,6 +905,7 @@ gw mv <worktree> <new-path>
|
|
|
868
905
|
```
|
|
869
906
|
|
|
870
907
|
**Examples:**
|
|
908
|
+
|
|
871
909
|
```bash
|
|
872
910
|
gw move feat-branch ../new-location
|
|
873
911
|
gw mv feat-branch ../new-location
|
|
@@ -875,19 +913,56 @@ gw mv feat-branch ../new-location
|
|
|
875
913
|
|
|
876
914
|
#### prune
|
|
877
915
|
|
|
878
|
-
Clean up worktree
|
|
916
|
+
Clean up worktree administrative data and optionally remove clean worktrees.
|
|
917
|
+
|
|
918
|
+
**Standard Mode** (without `--clean`):
|
|
919
|
+
Wraps `git worktree prune` to clean up administrative files for deleted worktrees.
|
|
920
|
+
|
|
921
|
+
**Clean Mode** (with `--clean`):
|
|
922
|
+
First runs `git worktree prune`, then removes ALL worktrees that have no uncommitted changes, no staged files, and no unpushed commits. Unlike `gw clean` (which is age-based), `gw prune --clean` removes worktrees regardless of age.
|
|
879
923
|
|
|
880
924
|
```bash
|
|
881
|
-
gw prune
|
|
925
|
+
gw prune [options]
|
|
882
926
|
```
|
|
883
927
|
|
|
928
|
+
**Options:**
|
|
929
|
+
|
|
930
|
+
- `--clean` - Enable clean mode (remove clean worktrees)
|
|
931
|
+
- `-n, --dry-run` - Preview what would be removed
|
|
932
|
+
- `-f, --force` - Skip confirmation prompt
|
|
933
|
+
- `-v, --verbose` - Show detailed output
|
|
934
|
+
- `-h, --help` - Show help
|
|
935
|
+
|
|
936
|
+
**Safety Features** (in clean mode):
|
|
937
|
+
|
|
938
|
+
- Default branch is protected (configured in `.gw/config.json`)
|
|
939
|
+
- Current worktree cannot be removed
|
|
940
|
+
- Bare repository is never removed
|
|
941
|
+
- Confirmation prompt before removal (defaults to yes, just press Enter to confirm)
|
|
942
|
+
|
|
884
943
|
**Examples:**
|
|
944
|
+
|
|
885
945
|
```bash
|
|
886
|
-
|
|
887
|
-
gw prune
|
|
888
|
-
gw prune --verbose
|
|
946
|
+
# Standard prune (cleanup administrative data)
|
|
947
|
+
gw prune
|
|
948
|
+
gw prune --verbose
|
|
949
|
+
|
|
950
|
+
# Clean mode (remove clean worktrees)
|
|
951
|
+
gw prune --clean # Remove all clean worktrees (with prompt)
|
|
952
|
+
gw prune --clean --dry-run # Preview what would be removed
|
|
953
|
+
gw prune --clean --force # Remove without confirmation
|
|
954
|
+
gw prune --clean --verbose # Show detailed output
|
|
889
955
|
```
|
|
890
956
|
|
|
957
|
+
**Comparison with `gw clean`:**
|
|
958
|
+
| Feature | `gw clean` | `gw prune --clean` |
|
|
959
|
+
|---------|-----------|-------------------|
|
|
960
|
+
| Age-based | Yes (configurable threshold) | No (removes all clean) |
|
|
961
|
+
| Safety checks | Yes | Yes |
|
|
962
|
+
| Protects default branch | No | Yes |
|
|
963
|
+
| Runs `git worktree prune` | No | Yes |
|
|
964
|
+
| Use case | Regular maintenance | Aggressive cleanup |
|
|
965
|
+
|
|
891
966
|
#### lock
|
|
892
967
|
|
|
893
968
|
Lock a worktree to prevent removal.
|
|
@@ -897,6 +972,7 @@ gw lock <worktree>
|
|
|
897
972
|
```
|
|
898
973
|
|
|
899
974
|
**Examples:**
|
|
975
|
+
|
|
900
976
|
```bash
|
|
901
977
|
gw lock feat-branch
|
|
902
978
|
gw lock --reason "Work in progress" feat-branch
|
|
@@ -911,6 +987,7 @@ gw unlock <worktree>
|
|
|
911
987
|
```
|
|
912
988
|
|
|
913
989
|
**Examples:**
|
|
990
|
+
|
|
914
991
|
```bash
|
|
915
992
|
gw unlock feat-branch
|
|
916
993
|
```
|
|
@@ -924,6 +1001,7 @@ gw repair [<path>]
|
|
|
924
1001
|
```
|
|
925
1002
|
|
|
926
1003
|
**Examples:**
|
|
1004
|
+
|
|
927
1005
|
```bash
|
|
928
1006
|
gw repair # Repair all worktrees
|
|
929
1007
|
gw repair /path/to/worktree # Repair specific worktree
|
|
@@ -964,117 +1042,36 @@ gw cd feat-manual
|
|
|
964
1042
|
|
|
965
1043
|
### Local Development & Testing
|
|
966
1044
|
|
|
967
|
-
When developing the tool, you can test changes locally without publishing by
|
|
1045
|
+
When developing the tool, you can test changes locally without publishing by using a shell alias. This allows you to use the `gw-dev` command with live code updates and full shell integration.
|
|
968
1046
|
|
|
969
|
-
####
|
|
1047
|
+
#### Shell Alias Method (Recommended)
|
|
970
1048
|
|
|
971
|
-
Create a shell alias that runs the Deno version directly
|
|
1049
|
+
Create a shell alias that runs the Deno version directly for instant feedback:
|
|
972
1050
|
|
|
973
1051
|
```bash
|
|
974
|
-
#
|
|
975
|
-
alias
|
|
1052
|
+
# Install shell integration for gw-dev
|
|
1053
|
+
# IMPORTANT: Don't create an alias yourself - the install-shell command creates a function for you
|
|
1054
|
+
# Make sure to use your actual path to gw-tools
|
|
1055
|
+
deno run --allow-all ~/path/to/gw-tools/packages/gw-tool/src/main.ts install-shell \
|
|
1056
|
+
--name gw-dev \
|
|
1057
|
+
--command "deno run --allow-all ~/path/to/gw-tools/packages/gw-tool/src/main.ts"
|
|
976
1058
|
|
|
977
1059
|
# Reload your shell
|
|
978
1060
|
source ~/.zshrc # or ~/.bashrc
|
|
979
1061
|
|
|
980
|
-
# Now you can use it anywhere
|
|
1062
|
+
# Now you can use it anywhere with full shell integration
|
|
981
1063
|
cd ~/some-project
|
|
1064
|
+
gw-dev add feat-branch # Output streams in real-time!
|
|
1065
|
+
gw-dev cd feat-branch # Navigates to the worktree
|
|
982
1066
|
gw-dev copy feat-branch .env
|
|
983
1067
|
```
|
|
984
1068
|
|
|
985
|
-
This gives you instant feedback - just edit the TypeScript files and run the command again.
|
|
986
|
-
|
|
987
|
-
#### Method 2: Symlink to Compiled Binary (Faster Execution)
|
|
988
|
-
|
|
989
|
-
Create a symlink to the compiled binary and recompile when needed:
|
|
990
|
-
|
|
991
|
-
```bash
|
|
992
|
-
# From the workspace root
|
|
993
|
-
nx run gw-tool:compile
|
|
994
|
-
|
|
995
|
-
# Create global symlink (one-time setup)
|
|
996
|
-
sudo ln -sf ~/path/to/gw-tools/dist/packages/gw-tool/gw /usr/local/bin/gw
|
|
997
|
-
|
|
998
|
-
# Now you can use `gw` globally
|
|
999
|
-
cd ~/some-project
|
|
1000
|
-
gw sync feat-branch .env
|
|
1001
|
-
|
|
1002
|
-
# When you make changes, recompile
|
|
1003
|
-
nx run gw-tool:compile
|
|
1004
|
-
# The symlink automatically points to the new binary
|
|
1005
|
-
```
|
|
1006
|
-
|
|
1007
|
-
#### Method 3: Development Wrapper Script (Best of Both Worlds)
|
|
1008
|
-
|
|
1009
|
-
Create a wrapper script that provides both speed and live updates:
|
|
1010
|
-
|
|
1011
|
-
```bash
|
|
1012
|
-
# Create ~/bin/gw (make sure ~/bin is in your PATH)
|
|
1013
|
-
cat > ~/bin/gw << 'EOF'
|
|
1014
|
-
#!/bin/bash
|
|
1015
|
-
# Check if we're in development mode (set GW_DEV=1 to use source)
|
|
1016
|
-
if [ "$GW_DEV" = "1" ]; then
|
|
1017
|
-
exec deno run --allow-all ~/path/to/gw-tools/packages/gw-tool/src/main.ts "$@"
|
|
1018
|
-
else
|
|
1019
|
-
exec ~/path/to/gw-tools/dist/packages/gw-tool/gw "$@"
|
|
1020
|
-
fi
|
|
1021
|
-
EOF
|
|
1022
|
-
|
|
1023
|
-
chmod +x ~/bin/gw
|
|
1024
|
-
|
|
1025
|
-
# Use compiled version (fast)
|
|
1026
|
-
gw sync feat-branch .env
|
|
1027
|
-
|
|
1028
|
-
# Use development version with live updates
|
|
1029
|
-
GW_DEV=1 gw sync feat-branch .env
|
|
1030
|
-
|
|
1031
|
-
# Or set it for your entire session
|
|
1032
|
-
export GW_DEV=1
|
|
1033
|
-
gw sync feat-branch .env
|
|
1034
|
-
```
|
|
1035
|
-
|
|
1036
|
-
#### Method 4: npm link (For Testing Installation)
|
|
1069
|
+
This gives you instant feedback - just edit the TypeScript files and run the command again. The shell integration provides the same experience as the installed version:
|
|
1037
1070
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
nx run gw-tool:compile-all
|
|
1043
|
-
|
|
1044
|
-
# Prepare npm package
|
|
1045
|
-
nx run gw-tool:npm-pack
|
|
1046
|
-
|
|
1047
|
-
# Link the package globally
|
|
1048
|
-
cd dist/packages/gw-tool/npm
|
|
1049
|
-
npm link
|
|
1050
|
-
|
|
1051
|
-
# Now `gw` is available globally via npm
|
|
1052
|
-
gw sync feat-branch .env
|
|
1053
|
-
|
|
1054
|
-
# When you make changes
|
|
1055
|
-
cd ~/path/to/gw-tools
|
|
1056
|
-
nx run gw-tool:compile-all
|
|
1057
|
-
nx run gw-tool:npm-pack
|
|
1058
|
-
# The link automatically uses the updated binaries
|
|
1059
|
-
|
|
1060
|
-
# To unlink when done
|
|
1061
|
-
npm unlink -g @gw-tools/gw
|
|
1062
|
-
```
|
|
1063
|
-
|
|
1064
|
-
#### Watch Mode for Active Development
|
|
1065
|
-
|
|
1066
|
-
Use the watch mode to automatically restart when files change:
|
|
1067
|
-
|
|
1068
|
-
```bash
|
|
1069
|
-
# Terminal 1: Run in watch mode
|
|
1070
|
-
nx run gw-tool:dev
|
|
1071
|
-
|
|
1072
|
-
# Terminal 2: Test in another project
|
|
1073
|
-
cd ~/some-project
|
|
1074
|
-
~/path/to/gw-tools/dist/packages/gw-tool/gw sync feat-branch .env
|
|
1075
|
-
```
|
|
1076
|
-
|
|
1077
|
-
**Pro tip**: Combine Method 3 (wrapper script) with watch mode by setting `GW_DEV=1` in your development shell.
|
|
1071
|
+
- Real-time streaming output (no buffering)
|
|
1072
|
+
- `gw-dev cd` navigation support
|
|
1073
|
+
- Auto-navigation after `gw-dev add`
|
|
1074
|
+
- Auto-navigation to repo root after `gw-dev remove`
|
|
1078
1075
|
|
|
1079
1076
|
### Available Scripts
|
|
1080
1077
|
|
|
@@ -1190,6 +1187,7 @@ npm publish --access public
|
|
|
1190
1187
|
For users who prefer Deno's native package manager.
|
|
1191
1188
|
|
|
1192
1189
|
1. **Add JSR configuration to `deno.json`:**
|
|
1190
|
+
|
|
1193
1191
|
```json
|
|
1194
1192
|
{
|
|
1195
1193
|
"name": "@your-scope/gw",
|
|
@@ -1281,15 +1279,16 @@ There are two types of commands you can add:
|
|
|
1281
1279
|
For commands with custom logic, follow the pattern used by existing commands:
|
|
1282
1280
|
|
|
1283
1281
|
1. **Create a new file** in `src/commands/` (e.g., `list.ts`):
|
|
1282
|
+
|
|
1284
1283
|
```typescript
|
|
1285
1284
|
// src/commands/list.ts
|
|
1286
1285
|
export async function executeList(args: string[]): Promise<void> {
|
|
1287
1286
|
// Check for help flag
|
|
1288
|
-
if (args.includes(
|
|
1287
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1289
1288
|
console.log(`Usage: gw list
|
|
1290
|
-
|
|
1289
|
+
|
|
1291
1290
|
List all git worktrees in the current repository.
|
|
1292
|
-
|
|
1291
|
+
|
|
1293
1292
|
Options:
|
|
1294
1293
|
-h, --help Show this help message
|
|
1295
1294
|
`);
|
|
@@ -1302,8 +1301,9 @@ For commands with custom logic, follow the pattern used by existing commands:
|
|
|
1302
1301
|
```
|
|
1303
1302
|
|
|
1304
1303
|
2. **Import and register** the command in `src/main.ts`:
|
|
1304
|
+
|
|
1305
1305
|
```typescript
|
|
1306
|
-
import { executeList } from
|
|
1306
|
+
import { executeList } from './commands/list.ts';
|
|
1307
1307
|
|
|
1308
1308
|
const COMMANDS = {
|
|
1309
1309
|
add: executeAdd,
|
|
@@ -1333,18 +1333,18 @@ For commands with custom logic, follow the pattern used by existing commands:
|
|
|
1333
1333
|
For simple pass-through commands that wrap git worktree operations, use the `git-proxy` utility:
|
|
1334
1334
|
|
|
1335
1335
|
1. **Create a new file** in `src/commands/` (e.g., `list.ts`):
|
|
1336
|
+
|
|
1336
1337
|
```typescript
|
|
1337
1338
|
// src/commands/list.ts
|
|
1338
1339
|
import { executeGitWorktree, showProxyHelp } from '../lib/git-proxy.ts';
|
|
1339
1340
|
|
|
1340
1341
|
export async function executeList(args: string[]): Promise<void> {
|
|
1341
1342
|
if (args.includes('--help') || args.includes('-h')) {
|
|
1342
|
-
showProxyHelp(
|
|
1343
|
-
'list',
|
|
1344
|
-
'list',
|
|
1345
|
-
'
|
|
1346
|
-
|
|
1347
|
-
);
|
|
1343
|
+
showProxyHelp('list', 'list', 'List all worktrees in the repository', [
|
|
1344
|
+
'gw list',
|
|
1345
|
+
'gw list --porcelain',
|
|
1346
|
+
'gw list -v',
|
|
1347
|
+
]);
|
|
1348
1348
|
Deno.exit(0);
|
|
1349
1349
|
}
|
|
1350
1350
|
|
|
@@ -1359,6 +1359,7 @@ For simple pass-through commands that wrap git worktree operations, use the `git
|
|
|
1359
1359
|
This approach requires minimal maintenance as it simply forwards all arguments to git.
|
|
1360
1360
|
|
|
1361
1361
|
**Tips**:
|
|
1362
|
+
|
|
1362
1363
|
- Look at [src/commands/root.ts](src/commands/root.ts) for a simple custom command
|
|
1363
1364
|
- Look at [src/commands/copy.ts](src/commands/copy.ts) for a complex command with argument parsing
|
|
1364
1365
|
- Look at [src/commands/list.ts](src/commands/list.ts) for a simple proxy command
|
package/bin/gw
ADDED
|
Binary file
|
package/install.js
CHANGED
|
@@ -176,12 +176,28 @@ async function install() {
|
|
|
176
176
|
async function installShellIntegration(binaryPath, retries = 3) {
|
|
177
177
|
const { spawn } = require('child_process');
|
|
178
178
|
|
|
179
|
+
// Check environment before attempting shell integration
|
|
180
|
+
const hasRequiredEnv = process.env.HOME || process.env.USERPROFILE;
|
|
181
|
+
const hasShell = process.env.SHELL;
|
|
182
|
+
|
|
183
|
+
if (!hasRequiredEnv) {
|
|
184
|
+
console.log(' Skipping shell integration: HOME environment variable not set');
|
|
185
|
+
console.log(' Run "gw install-shell" manually after installation');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!hasShell) {
|
|
190
|
+
console.log(' Skipping shell integration: SHELL environment variable not set');
|
|
191
|
+
console.log(' Run "gw install-shell" manually after installation');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
179
195
|
return new Promise((resolve) => {
|
|
180
196
|
let child;
|
|
181
197
|
|
|
182
198
|
try {
|
|
183
|
-
child = spawn(binaryPath, ['install-shell'
|
|
184
|
-
stdio: 'inherit',
|
|
199
|
+
child = spawn(binaryPath, ['install-shell'], {
|
|
200
|
+
stdio: ['inherit', 'inherit', 'pipe'], // stdin, stdout, stderr
|
|
185
201
|
});
|
|
186
202
|
} catch (err) {
|
|
187
203
|
// Catch synchronous spawn errors (e.g., ETXTBSY thrown immediately)
|
|
@@ -191,20 +207,28 @@ async function installShellIntegration(binaryPath, retries = 3) {
|
|
|
191
207
|
}, 200);
|
|
192
208
|
return;
|
|
193
209
|
}
|
|
194
|
-
console.log(
|
|
195
|
-
|
|
196
|
-
);
|
|
210
|
+
console.log(' Shell integration setup encountered an issue.');
|
|
211
|
+
console.log(' You can install it manually later with: gw install-shell');
|
|
197
212
|
resolve();
|
|
198
213
|
return;
|
|
199
214
|
}
|
|
200
215
|
|
|
216
|
+
let stderrOutput = '';
|
|
217
|
+
child.stderr.on('data', (data) => {
|
|
218
|
+
stderrOutput += data.toString();
|
|
219
|
+
// Also display it immediately
|
|
220
|
+
process.stderr.write(data);
|
|
221
|
+
});
|
|
222
|
+
|
|
201
223
|
child.on('close', (code) => {
|
|
202
224
|
if (code === 0) {
|
|
203
225
|
console.log('✓ Shell integration installed!');
|
|
204
226
|
} else {
|
|
205
|
-
console.log(
|
|
206
|
-
|
|
207
|
-
|
|
227
|
+
console.log(' Shell integration failed with exit code:', code);
|
|
228
|
+
if (stderrOutput) {
|
|
229
|
+
console.log(' Error:', stderrOutput.trim());
|
|
230
|
+
}
|
|
231
|
+
console.log(' You can install it manually later with: gw install-shell');
|
|
208
232
|
}
|
|
209
233
|
resolve();
|
|
210
234
|
});
|
|
@@ -215,9 +239,8 @@ async function installShellIntegration(binaryPath, retries = 3) {
|
|
|
215
239
|
await new Promise((r) => setTimeout(r, 200));
|
|
216
240
|
return installShellIntegration(binaryPath, retries - 1).then(resolve);
|
|
217
241
|
}
|
|
218
|
-
console.log(
|
|
219
|
-
|
|
220
|
-
);
|
|
242
|
+
console.log(' Shell integration setup encountered an issue.');
|
|
243
|
+
console.log(' You can install it manually later with: gw install-shell');
|
|
221
244
|
resolve();
|
|
222
245
|
});
|
|
223
246
|
});
|